如何从python (2.5) 的subprocess.Popen中获取“实时”信息

47 投票
10 回答
14484 浏览
提问于 2025-04-15 11:39

我想用 subprocess 模块来做以下事情:

  1. 创建一个新的进程,这个进程可能需要很长时间才能完成。
  2. 捕获 stdout(标准输出)或者 stderr(错误输出),或者两者都捕获,可以一起也可以分开。
  3. 在子进程的数据到达时,实时处理这些数据,可能在每接收到一行时触发事件(比如在 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

撰写回答