如何从python (2.5) 的subprocess.Popen中获取“实时”信息
我想用 subprocess 模块来做以下事情:
- 创建一个新的进程,这个进程可能需要很长时间才能完成。
- 捕获
stdout
(标准输出)或者stderr
(错误输出),或者两者都捕获,可以一起也可以分开。 - 在子进程的数据到达时,实时处理这些数据,可能在每接收到一行时触发事件(比如在 wxPython 中),或者暂时只是打印出来。
我用 Popen 创建过进程,但如果我使用 communicate() 方法,数据会在进程结束后一次性全部到来。
如果我创建一个单独的线程,使用阻塞的 readline()
来读取 myprocess.stdout
(通过 stdout = subprocess.PIPE
),我也无法在进程结束之前获取任何行的数据。(无论我设置的缓冲区大小是什么)
有没有一种方法可以处理这个问题,既不复杂,又能在多个平台上良好运行?
10 个回答
2
听起来这个问题可能是因为子进程使用了缓冲输出。如果子进程产生的输出量比较小,这些输出可能会被暂时存储起来,直到子进程结束。你可以在这里找到一些相关的背景信息:
7
标准输出(stdout)会被缓存,也就是说,直到这个缓存区满了或者子进程结束之前,你不会看到任何输出。
你可以尝试从子进程中强制刷新 stdout
,或者使用错误输出(stderr),或者把标准输出设置为不缓存模式。
8
更新一下,下面的代码在Windows上似乎不太好使。
class ThreadWorker(threading.Thread):
def __init__(self, callable, *args, **kwargs):
super(ThreadWorker, self).__init__()
self.callable = callable
self.args = args
self.kwargs = kwargs
self.setDaemon(True)
def run(self):
try:
self.callable(*self.args, **self.kwargs)
except wx.PyDeadObjectError:
pass
except Exception, e:
print e
if __name__ == "__main__":
import os
from subprocess import Popen, PIPE
def worker(pipe):
while True:
line = pipe.readline()
if line == '': break
else: print line
proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout_worker = ThreadWorker(worker, proc.stdout)
stderr_worker = ThreadWorker(worker, proc.stderr)
stdout_worker.start()
stderr_worker.start()
while True: pass