Подтвердить что ты не робот

Python: как читать stdout без блокировки из другого процесса?

Во время выполнения процесса я хотел бы прочитать его stdout и записать его в файл. Любая моя попытка, однако, не удалась, потому что независимо от того, что я пробовал, как только я попытался прочитать из stdout, он заблокирован до завершения процесса.

Вот фрагмент того, что я пытаюсь сделать. (Первая часть - это просто python script, который пишет что-то в stdout.)

import subprocess

p = subprocess.Popen('python -c \'\
from time import sleep\n\
for i in range(3):\n\
    sleep(1)\n\
    print "Hello", i\
\'', shell = True, stdout = subprocess.PIPE)

while p.poll() == None:
    #read the stdout continuously
    pass

print "Done"

Я знаю, что есть несколько вопросов, которые касаются одного и того же предмета. Однако ни один из найденных мной не смог ответить на мой вопрос.

4b9b3361

Ответ 1

Что происходит, буферизация на стороне писателя. Поскольку вы пишете такие небольшие куски из небольшого фрагмента кода, базовый объект FILE выполняет буферизацию вывода до конца. Следующее работает так, как вы ожидаете.

#!/usr/bin/python

import sys
import subprocess

p = subprocess.Popen("""python -c '
from time import sleep ; import sys
for i in range(3):
    sleep(1)
    print "Hello", i
    sys.stdout.flush()
'""", shell = True, stdout = subprocess.PIPE)

while True:
    inline = p.stdout.readline()
    if not inline:
        break
    sys.stdout.write(inline)
    sys.stdout.flush()

print "Done"

Однако вы можете не ожидать правильной вещи. Буферизация там, чтобы уменьшить количество системных вызовов, чтобы сделать систему более эффективной. Вам действительно важно, чтобы весь текст буферизовался до конца, прежде чем вы напишете его в файл? Вы все еще не получаете весь вывод в файле?

Ответ 2

следующий код будет печатать stdout по очереди, поскольку подпроцесс работает до тех пор, пока метод readline() не возвращает пустую строку:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
    print line
p.stdout.close()
print 'Done'

обновление, связанное с вашим вопросом, лучше:

import subprocess

p = subprocess.Popen(['python'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
p.stdin.write("""
from time import sleep ; import sys
for i in range(3):
    sleep(1)
    print "Hello", i
    sys.stdout.flush()
""")
p.stdin.close()
for line in iter(p.stdout.readline, ''):
    print line
p.stdout.close()
print 'Done'

Ответ 3

Вы можете использовать subprocess.communicate(), чтобы получить вывод из stdout. Что-то вроде:

while(p.poll() == None):
    #read the stdout continuously
    print(p.communicate()[0])
    pass

Дополнительная информация доступна по адресу: http://docs.python.org/library/subprocess.html