Wie kann ich Lesen alle zur Verfügung stehen Daten aus Teilprozess.Popen.stdout (non-blocking)?
Ich brauche einen Weg, entweder Lesen Sie alle derzeit verfügbaren Zeichen im Datenstrom erstellt von Popen oder um herauszufinden, wie viele Zeichen noch in den Puffer.
Werdegang:
Ich möchte die remote-Steuerung einer interaktiven Anwendung in Python. So weit ich verwendet Popen zum erstellen eines neuen unterprozesses:
process=subprocess.Popen(["python"],shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, cwd=workingDir)
(Ich bin nicht wirklich ab von python, aber der eigentliche interaktive Schnittstelle ist ähnlich.)
Im moment lese ich 1 byte, bis ich erkennen, dass der Prozess erreicht hat, in der Eingabeaufforderung:
output = ""
while output[-6:]!="SCIP> ":
output += process.stdout.read(1)
sys.stdout.write(output[-1])
return output
Dann beginne ich einen längeren Berechnung über process.stdin.write("command\n")
.
Mein problem ist, dass ich nicht prüfen, ob die Berechnung fertig ist oder nicht, denn ich kann nicht überprüfen, ob das Letzte Zeichen in den stream der Eingabeaufforderung oder nicht. read()
oder read(n)
blockiert mein thread bis zum erreichen von EOF, die es nie werden, weil das interaktive Programm wird nicht enden, bis es gesagt wird. Suchen Sie die Aufforderung in der Weise der obigen Schleife wird nicht funktionieren, weil sich die Eingabeaufforderung wird nur auftreten, nachdem der Berechnung.
Ideale Lösung, die es mir erlauben würde, die zum Lesen aller verfügbaren Zeichen aus dem stream und sofort eine leere Zeichenfolge zurück, wenn es nichts zu Lesen.
InformationsquelleAutor der Frage Perseids | 2010-06-19
Du musst angemeldet sein, um einen Kommentar abzugeben.
Herumstöbern fand ich dieses wirklich schöne Lösung
Persistente python-subprocess
vermeidet die Blockierung Problem alle zusammen mit
fcntl
die Datei-Attribute auf den Teilprozess pipes, non-blocking-Modus, keine zusätzlichen threads oder Abfragen erforderlich. Ich könnte etwas fehlen, aber es hat sich gelöst, meine interactive Prozesssteuerung problem.InformationsquelleAutor der Antwort Daniel Genin
Inkrementellen Parsen von Popen stdout ist kein problem, wirklich. Legen Sie einfach ein Rohr in einen thread und es Peeling durch Ausgabe, auf der Suche nach Trennzeichen. Je nach Vorliebe, kann es Rohr in ein anderes Rohr /Datei-oder wie stellen die analysierten "Brocken" auf den "stack" im asynchronen Modus. Hier ist ein Beispiel für asynchrone "chunking" von stdout auf der Basis von benutzerdefinierten Trennzeichen:
Edit: entfernt die fehlerhaften Wortschwall über "schreiben in proc stdin ist ein one-time-thing"
InformationsquelleAutor der Antwort ddotsenko
Gibt es eine andere mögliche Lösung, aber es kann erfordern, dass Sie neu anordnen Ihr Programm ein bisschen.
Wenn Sie mehrere Quellen von I/O (Datei-Deskriptoren, Steckdosen, etc.), und Sie warten auf Sie alle auf einmal, verwenden Sie die Python - wählen Sie Modul. Könnten Sie (zum Beispiel) legen Sie den standard-input (für Lesung aus dem terminal) und das Rohr (aus dem Teilprozess) in eine Liste ein, und warten Sie für die Eingabe bereit zu sein, die auf entweder einer von Ihnen.
select
blockiert wird, bis die I/O ist auf jedem der Deskriptoren in der Liste. Dann Scannen Sie die Liste, suchen für diejenigen, die verfügbaren Daten.Dieser Ansatz erweist sich sehr effizient-viel mehr so als polling einen Datei-Deskriptor, um zu sehen, ob irgendwelche Daten. Es hat auch die Tugend der Einfachheit; das heißt, Sie können erreichen, was Sie wollen, mit einem minimum an code. Einfacher code bedeutet weniger Chancen für bugs.
InformationsquelleAutor der Antwort Brian Clapper
Es ist nicht richtig, dass read() blockiert, bis EOF - es blockiert, bis es genügend Daten, die es braucht - und von der anderen Seite ist es möglich, dass einige Daten in den Puffern (es ist nicht gespült, nur weil Sie endete print mit new line).
Warum nicht versuchen, auf das Kind Druck so etwas wie
"### OVER ###\n"
und dannstdout.flush()
dann auf der übergeordneten Seite sammeln, bis Sie sehen, der ÜBER token, sagen mit''.join(i for i in iter(process.stdout.readline, '### OVER ###\n'))
InformationsquelleAutor der Antwort Nas Banov
Ich habe versucht, eine Menge von Ansätzen, wie eine nicht-blockierende
stdout
durch die folgenden:Aber die einzige funktionierende Lösung ist beschrieben hier:
Dann:
InformationsquelleAutor der Antwort Exterminator13
Ich glaube nicht, dass readline() blockiert den Prozess erforderlich sind.
Früher habe ich versucht,
aber das scheint zu hängen, bis der Prozess beendet ist.
InformationsquelleAutor der Antwort midtiby