我有一个python程序,它使用Popen
启动子进程,并在产生时几乎实时地使用它们的输出。有关循环的代码是:在popen.stdout.readline上检测流的结束
def run(self, output_consumer):
self.prepare_to_run()
popen_args = self.get_popen_args()
logging.debug("Calling popen with arguments %s" % popen_args)
self.popen = subprocess.Popen(**popen_args)
while True:
outdata = self.popen.stdout.readline()
if not outdata and self.popen.returncode is not None:
# Terminate when we've read all the output and the returncode is set
break
output_consumer.process_output(outdata)
self.popen.poll() # updates returncode so we can exit the loop
output_consumer.finish(self.popen.returncode)
self.post_run()
def get_popen_args(self):
return {
'args': self.command,
'shell': False, # Just being explicit for security's sake
'bufsize': 0, # More likely to see what's being printed as it happens
# Not guarantted since the process itself might buffer its output
# run `python -u` to unbuffer output of a python processes
'cwd': self.get_cwd(),
'env': self.get_environment(),
'stdout': subprocess.PIPE,
'stderr': subprocess.STDOUT,
'close_fds': True, # Doesn't seem to matter
}
这对我的生产机器的伟大工程,但我的开发机器上,调用.readline()
挂起当某些子进程结束。也就是说,它会成功处理所有的输出,包括最后一行输出“过程完成”,但会再次轮询readline
并永不返回。对于我调用的大多数子进程,此方法在开发机器上正确退出,但始终无法退出,因为一个复杂的bash脚本本身会调用多个子进程。
值得注意的是,popen.returncode
在输出结束之前被设置为许多行的非None
值(通常为0
)。所以我不能只是在设置时跳出循环,否则我会失去在流程结束时吐出的所有东西,并且仍然等待读取。问题是,当我冲洗缓冲区时,我不知道我什么时候结束,因为最后一次致电readline()
挂起。调用read()
也挂起。打电话给read(1)
让我最后一个字符出来,但也在最后一行后挂起。 popen.stdout.closed
总是False
。我怎么能告诉我什么时候结束?
所有系统都在Ubuntu 12.04LTS上运行python 2.7.3。 FWIW,stderr
正在与stdout
合并使用stderr=subprocess.STDOUT
。
为什么区别?由于某种原因它没有关闭stdout
?子子过程可以做些什么来保持它以某种方式打开?难道是因为我正在从我的开发箱上的终端启动进程,但在生产中,它通过supervisord
作为守护进程启动?这将改变管道的处理方式吗?如果是的话,我如何使它们正常化?
是不是你正在阅读从不再存在的工艺线的问题? – 2013-02-13 16:24:25
我不这么认为。如果这个错误很简单,它会一直到处都是失败的。 – Leopd 2013-02-13 16:59:57
为什么你不能只打破''不outdata'' – sotapme 2013-02-13 18:55:32