Прошло много времени с тех пор, как я в последний раз работал с Python, но я думаю, что проблема связана с оператором for line in proc.stdout
, который читает весь ввод перед его итерацией по нему. Решение состоит в том, чтобы вместо этого использовать readline()
:
#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
while True:
line = proc.stdout.readline()
if line != '':
#the real code does filtering here
print "test:", line.rstrip()
else:
break
Конечно, вам все равно придется иметь дело с буферизацией подпроцесса.
Примечание: в соответствии с документацией решение с итератором должно быть эквивалентно использованию readline()
, за исключением буфера чтения, но (или именно из-за этого) предлагаемое изменение произвело для меня разные результаты (Python 2.5 в Windows XP).
Немного опоздал на вечеринку, но был удивлен, не увидев, что я считаю самым простым решением здесь:
import io
import subprocess
proc = subprocess.Popen(["prog", "arg"], stdout=subprocess.PIPE)
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): # or another encoding
# do something with line
Следующая версия ответа Rômulo работает для меня на Python 2 и 3 (2.7.12 и 3.6.1):
import os
import subprocess
process = subprocess.Popen(command, stdout=subprocess.PIPE)
while True:
line = process.stdout.readline()
if line != b'':
os.write(1, line)
else:
break
Вы хотите передать эти дополнительные параметры в subprocess.Popen
:
bufsize=1, universal_newlines=True
Затем вы можете выполнять итерацию, как в вашем примере. (Протестировано с помощью Python 3.5)
Я попробовал это с python3, и он работал, source
def output_reader(proc):
for line in iter(proc.stdout.readline, b''):
print('got line: {0}'.format(line.decode('utf-8')), end='')
def main():
proc = subprocess.Popen(['python', 'fake_utility.py'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
t = threading.Thread(target=output_reader, args=(proc,))
t.start()
try:
time.sleep(0.2)
import time
i = 0
while True:
print (hex(i)*512)
i += 1
time.sleep(0.5)
finally:
proc.terminate()
try:
proc.wait(timeout=0.2)
print('== subprocess exited with rc =', proc.returncode)
except subprocess.TimeoutExpired:
print('subprocess did not terminate in time')
t.join()
Действительно, если вы отсортировали итератор, тогда буферизация теперь может быть вашей проблемой. Вы можете сказать python в подпроцессе, чтобы не буферировать его вывод.
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
становится
proc = subprocess.Popen(['python','-u', 'fake_utility.py'],stdout=subprocess.PIPE)
Мне это нужно, когда вы вызываете python из python.