Mein Python-Skript verwendet einen Unterprozess, um ein Linux-Dienstprogramm aufzurufen, das sehr laut ist. Ich möchte die gesamte Ausgabe in einer Protokolldatei speichern und dem Benutzer einen Teil davon anzeigen. Ich dachte, das Folgende würde funktionieren, aber die Ausgabe wird in meiner Anwendung erst angezeigt, wenn das Dienstprogramm eine erhebliche Menge an Ausgabe erzeugt hat.
#fake_utility.py, just generates lots of output over time
import time
i = 0
while True:
print hex(i)*512
i += 1
time.sleep(0.5)
#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
for line in proc.stdout:
#the real code does filtering here
print "test:", line.rstrip()
Das Verhalten, das ich wirklich möchte, besteht darin, dass das Filterskript jede Zeile druckt, wenn sie vom Unterprozess empfangen wird. Sorta mag was tee
macht aber mit Python Code.
Was vermisse ich? Ist das überhaupt möglich?
Aktualisieren:
Wenn a sys.stdout.flush()
zu fake_utility.py hinzugefügt wird, hat der Code das gewünschte Verhalten in Python 3.1. Ich benutze Python 2.6. Sie würden denken, dass die Verwendung proc.stdout.xreadlines()
genauso funktioniert wie py3k, aber das funktioniert nicht.
Update 2:
Hier ist der minimale Arbeitscode.
#fake_utility.py, just generates lots of output over time
import sys, time
for i in range(10):
print i
sys.stdout.flush()
time.sleep(0.5)
#display out put line by line
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
#works in python 3.0+
#for line in proc.stdout:
for line in iter(proc.stdout.readline,''):
print line.rstrip()
quelle
print line,
anstelle vonprint line.rstrip()
(Hinweis: Komma am Ende) verwenden.subprocess.communicate()
Antworten:
Es ist lange her, seit ich das letzte Mal mit Python gearbeitet habe, aber ich denke, das Problem liegt in der Anweisung
for line in proc.stdout
, die die gesamte Eingabe liest, bevor sie darüber iteriert. Die Lösung besteht darin,readline()
stattdessen Folgendes zu verwenden :Natürlich müssen Sie sich noch mit der Pufferung des Unterprozesses befassen.
Hinweis: Gemäß der Dokumentation sollte die Lösung mit einem Iterator mit
readline()
Ausnahme des Vorauslesepuffers der Verwendung entsprechen, aber (oder genau aus diesem Grund) die vorgeschlagene Änderung führte für mich zu unterschiedlichen Ergebnissen (Python 2.5 unter Windows XP).quelle
file.readline()
vs.for line in file
siehe bugs.python.org/issue3907 (kurz: es funktioniert unter Python3; Verwendungio.open()
unter Python 2.6+)for line in iter(proc.stdout.readline, ''):
.for line in proc.stdout
unter Python 3 verwenden (es gibt keinen Read-Ahead-Fehler). 2. Unter'' != b''
Python 3 - Kopieren Sie den Code nicht blind und fügen Sie ihn ein - überlegen Sie, was er tut und wie er funktioniert.iter(f.readline, b'')
Lösung ist ziemlich offensichtlich (und funktioniert auch auf Python 2, wenn jemand interessiert ist). In meinem Kommentar ging es nicht darum, Ihre Lösung zu beschuldigen (Entschuldigung, wenn es so aussah, das habe ich jetzt auch gelesen!), Sondern darum, das Ausmaß der Symptome zu beschreiben, die in diesem Fall ziemlich schwerwiegend sind (die meisten Py2 / 3 Probleme führen zu Ausnahmen, während sich hier eine gut erzogene Schleife in endlos geändert hat und die Speicherbereinigung Probleme hat, die Flut neu erstellter Objekte zu bekämpfen, was zu Schwankungen der Speichernutzung mit langer Periode und großer Amplitude führt.Etwas spät zur Party, war aber überrascht, nicht zu sehen, was meiner Meinung nach die einfachste Lösung hier ist:
(Dies erfordert Python 3.)
quelle
AttributeError: 'file' object has no attribute 'readable'
bekomme : py2.7TextIOWrapper
oder nicht. Sie können die Ausnahme einfach behandeln.Wenn Sie den Iterator aussortiert haben, könnte die Pufferung jetzt Ihr Problem sein. Sie können die Python im Unterprozess anweisen, ihre Ausgabe nicht zu puffern.
wird
Ich habe dies benötigt, wenn ich Python aus Python heraus aufgerufen habe.
quelle
Sie möchten diese zusätzlichen Parameter übergeben an
subprocess.Popen
:Dann können Sie wie in Ihrem Beispiel iterieren. (Getestet mit Python 3.5)
quelle
Eine Funktion , die Iterieren über beide ermöglicht
stdout
undstderr
gleichzeitig, in Echtzeit, zeilenFür den Fall , müssen Sie den Ausgabestrom für beide bekommen
stdout
undstderr
zur gleichen Zeit können Sie die folgende Funktion verwenden.Die Funktion verwendet Warteschlangen, um beide Popen-Pipes zu einem einzigen Iterator zusammenzuführen.
Hier erstellen wir die Funktion
read_popen_pipes()
:read_popen_pipes()
in Benutzung:quelle
Sie können auch Zeilen ohne Schleife lesen. Funktioniert in Python3.6.
quelle
list_of_strings = [x.decode('utf-8').rstrip('\n') for x in iter(process.stdout.readlines())]
Ich habe es mit Python3 versucht und es hat funktioniert, Quelle
quelle
Die folgende Änderung von Rômulos Antwort funktioniert für mich unter Python 2 und 3 (2.7.12 und 3.6.1):
quelle
Keine Ahnung, wann dies dem Unterprozessmodul hinzugefügt wurde, aber mit Python 3 sollten Sie in Ordnung sein mit
proc.stdout.splitlines()
:quelle