最后,我能够使用线程生成多个子进程并将其stdout实时地发送到python中。
我有一个dicts列表,其中包含生成子进程所需的所有数据结构以及从管道中读取的线程。我想运行的特定程序需要几个小时才能完成,所以我可以忍受stdout每4096字节只刷一次的事实。
所以这是一些剥离的代码:
from time import sleep
import subprocess
from threading import Thread
from Queue import Queue, Empty
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def queue_get_all(queue):
items = []
while True:
try:
items.append(queue.get_nowait())
except Empty, e:
break
return items
worklist=[
{
'cmd' :r'command 1',
'pid' :None,
'queue' :None,
'thread' :None
},{
'cmd' :r'command 2',
'pid' :None,
'queue' :None,
'thread' :None
},{
'cmd' :r'command 3',
'pid' :None,
'queue' :None,
'thread' :None
}
]
for work in worklist:
work['pid'] = subprocess.Popen(work['cmd'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,bufsize=0)
work['queue'] = Queue()
work['thread'] = Thread(target=enqueue_output, args=(work['pid'].stdout, work['queue']))
work['thread'].daemon = True
work['thread'].start()
finalflush = False
while True:
for work in worklist:
lines = queue_get_all(work['queue'])
for line in lines:
print line
if all(item['pid'].poll() is not None for item in worklist):
if finalflush == False:
sleep(10)
finalflush = True
continue
else:
break
for work in worklist:
work['pid'].wait()
所以我面临的问题是,一旦所有流程完成,因此all(item['pid'].poll() is not None for item in worklist)
为真。 stdout管道中仍然可能存在一些尚未被我的线程读取的信息。
我的修复是在所有子进程完成后等待10秒,然后最后一次运行循环。这可能不会导致任何问题,但我不是那么喜欢它,我想知道我是否可以做一个真正的修复,所以我的线程被迫在子进程完成后再次读取!