2016-07-13 20 views
1

Gibt es einen Best-Practices-Ansatz für die Abfrage von stdout/stderr von einem subprocess.Popen sowie einem zmq-Socket?Interleaving stdout von Popen mit Nachrichten von ZMQ recv

In meinem Fall habe ich mein Hauptprogramm einen Popen Subprozess erzeugen. Der Subprozess veröffentlicht Nachrichten über zmq, die ich dann in meinem Hauptprogramm abonnieren möchte.

Warten auf mehreren ZMQ Buchsen nicht mit der zmq.Poller kompliziert, aber wenn ich das mit der Ausgabe von meinem subprocess verschachteln wollen selbst, ich bin nicht sicher, wie es in der besten Art und Weise zu tun, ohne wartet oder mit unnötigen Schleifen zu riskieren.

Am Ende würde Ich mag es zu benutzen, wie so:

process = Popen([prog, '--publish-to', 'tcp://127.0.0.1:89890'], 
     stdout=subprocess.PIPE, stderr=subprocess.PIPE, ...) 
for (origin, data) in interleave(process, 'tcp://127.0.0.1:89890'): 
    if origin == 'STDOUT': pass 
    if origin == 'STDERR': pass 
    if origin == 'ZMQ': pass 

prog --publish-to tcp://127.0.0.1:89890 wird dann eine zmq.PUB Buchse öffnen und Daten veröffentlichen, während die Verschachtelung Funktion dieser subscribe wird und abfragen auch für stdout und stderr , yield, welche Daten auch immer zuerst eingehen.

Ich weiß, wie man interleave mit mehreren Daemon-Threads und Warteschlangen definiert, aber ich weiß nicht, ob dieser Ansatz einige Vorbehalte in Bezug auf Lazy lesen (dh. Stdout möglicherweise nicht bis zum Ende des Programms verarbeitet werden?) oder andere Dinge, über die ich noch nicht nachgedacht habe (das scheint für eine solche Aufgabe auch ziemlich viel Overhead zu sein).

Ich werde für alle Ideen oder Erkenntnisse dankbar sein.

Ich ziele zumindest auf Python 3.3/3.4, aber wenn dies mit den neuen async/await-Tools viel einfacher wird, könnte ich auch Python 3.5 für den Code verwenden.

+0

Sie können den Integer-Dateideskriptor mithilfe von 'process.stdout.fileno()' abrufen. Wenn Sie den Dateideskriptor des zmq-Sockets abrufen können, können Sie einen Aufruf 'select.select ((fd1, d2, fd3),(),(), None)' ausführen, um auf den ersten Aufruf zu warten. Wenn es keine Möglichkeit gibt, den Dateideskriptor des zmq-Sockets abzurufen, können Sie zwei oder drei Threads erstellen, die beide aus einer Quelle lesen (und blockiert werden) und gelesene Daten in eine "Warteschlange" stellen. – pts

+0

Hmm, wird "Auswahl" auch auf Windows funktionieren? Das wäre leider ein Stopper. – Debilski

+0

Siehe auch: http://StackOverflow.com/Questions/9448247/zeromq-Zmq-Poller-Stdin – Debilski

Antwort

1

Verwenden Sie zmq.Poller: http://pyzmq.readthedocs.io/en/latest/api/zmq.html#polling. Sie können zmq-Sockets und native Dateideskriptoren (z. B. process.stdout.fileno() und process.stderr.fileno()) dort registrieren, und es wird warten, bis die Eingabe für mindestens eine der registrierten Quellen verfügbar ist.

Ich weiß nicht, ob es in Windows funktioniert, sollten Sie versuchen.

+0

Sollte nicht unter Windows arbeiten, leider, aber ich habe zumindest eine Abhilfe gefunden. Vielen Dank. http://stackoverflow.com/a/20807648/200266 – Debilski