基本上我想编写一个函数,将subprocess.Popen
的stdout和stderr(或者一般情况下是任何输入文件描述符)合并到一个生成(file_descriptor, line)
元组的生成器中。
我的第一次尝试看起来像这样: 从选择导入选择 导入子流程
def _merge_proc_output( process ):
inputs = (process.stdout, process.stderr)
while process.poll() is None:
for f in select(inputs , (), () )[0]:
line = f.readline()
if len(line): yield f, line
它似乎大部分时间都有效。对于10次运行,只有一次被破坏(点是随机)。偶尔它会错过某些线条而我认为它总是排在最后。不幸的是,这不是我能够一致地重现的东西,因此调试非常困难。
任何人都可以看到上面的代码有什么问题导致它从一个流的末尾删除行?
目前我使用更多资源饥饿和冗长的代码,但更便携:
import subprocess
import threading
from Queue import Queue
def _merge_proc_output( process ):
q = Queue()
def push(fd):
for l in fd:
q.put((fd, l))
q.put(None)
pipes = (process.stdout, process.stderr)
threads = [ threading.Thread( target = push, args = (fd,) ) for fd in pipes ]
[ t.start() for t in threads ]
for t in threads:
while True:
w = q.get()
if w is None:
break
yield w
[ t.join() for t in threads ]
这似乎工作正常(或者至少我还没有注意到问题)。我仍然想知道我的原始代码有什么问题。
P.S。如果您发现第二个解决方案的问题,请对此进行评论。
修改
嗯,我可能知道它为什么会发生。假设我只观察到最后一行丢失,可能是process.poll()
返回了一些内容,但这些流的输出缓冲区中仍有东西。
我通过添加尝试从输出流中读取所有内容的循环来修改我的原始函数:
def _merge_proc_output( process ):
inputs = (process.stdout, process.stderr)
while process.poll() is None:
for f in select(inputs , (), () )[0]:
line = f.readline()
if len(line): yield f, line
for i in inputs:
for l in i:
yield i,l
我必须有一些游戏来检查这是否能解决我的问题。
答案 0 :(得分:1)
当子进程终止时,您立即停止读取其输出。这意味着如果你还没有读完已经制作完成的内容,你就会在最后丢失这些内容。