Я хочу использовать subprocess.Popen
для запуска процесса со следующими требованиями.Нестандартные трубы Popen
Я хочу конвейерный
stdout
иstderr
обратно к вызывающемуPopen
, как проходит процесс.Я хочу убить процесс после
timeout
секунд, если он все еще работает.
Я пришел к выводу, что недостаток в subprocess
API означает, что он не может выполнить эти два требования одновременно. Рассмотрим следующие игрушечные программы:
chatty.py
while True:
print 'Hi'
silence.py
while True:
pass
caller.py
import subprocess
import time
def go(command, timeout=60):
proc = subprocess.Popen(command, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
start = time.time()
while proc.poll() is None:
print proc.stdout.read(1024) # <----- Line of interest
if time.time() - start >= timeout:
proc.kill()
break
else:
time.sleep(1)
Рассмотрим отмеченную строку выше.
Если он включен,
go('python silence.py')
будет висеть вечно - не только 60 секунд - потому чтоread
является блокировка вызова до либо1024
байт или конца потока, и ни один никогда не приходит.Если будет прокомментировано,
go('python chatty.py')
будет распечатывать'Hi'
снова и снова, но как он может быть передан обратно по мере его создания?proc.communicate()
блокируется до конца потока.
Я был бы счастлив с решением, которое заменяет требование (1) выше «В том случае, когда тайм-аут не произойдет, я хочу, чтобы получить stdout
и stderr
раз алгоритма заканчивается.» Даже это было проблематично. Моя попытка внедрения приведена ниже.
speech.py
for i in xrange(0, 10000):
print 'Hi'
caller2.py
import subprocess
import time
def go2(command, timeout=60):
proc = subprocess.Popen(command, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
start = time.time()
while True:
if proc.poll() is not None:
print proc.communicate()
break
elif time.time() - start >= timeout:
proc.kill()
break
else:
time.sleep(1)
Но даже это все еще есть проблемы. Хотя python speech.py
работает всего за пару секунд, go2('python speech.py')
занимает 60 секунд. Это связано с тем, что вызов print 'Hi'
в speech.py
блокируется до тех пор, пока не будет вызван proc.communicate()
, когда процесс будет убит. С proc.stdout.read
была проблема, продемонстрированная ранее с silence.py
, я действительно не понимаю, как это сделать.
Как я могу получить как stdout
, так и stderr
и поведение таймаута?
Выглядит многообещающе. Попытка этого завтра. –