6

我有一些使用 subprocess 模块运行的命令。然后我想循环输出的行。文档说不要做 data_stream.stdout.read 我不是,但我可能正在做一些调用它的事情。我正在像这样循环输出:

for line in data_stream.stdout:
   #do stuff here
   .
   .
   .

这是否会导致死锁,例如从 data_stream.stdout 读取,或者是否为这种循环设置了 Popen 模块,以便它使用通信代码但为您处理它的所有调用?

4

4 回答 4

9

如果您正在与您的子进程通信,您必须担心死锁,即,如果您正在写入标准输入以及从标准输出读取。因为这些管道可能会被缓存,所以进行这种双向通信是非常禁忌的:

data_stream = Popen(mycmd, stdin=PIPE, stdout=PIPE)
data_stream.stdin.write("do something\n")
for line in data_stream:
  ...  # BAD!

但是,如果您在构建 data_stream 时没有设置标准输入(或标准错误),应该没问题。

data_stream = Popen(mycmd, stdout=PIPE)
for line in data_stream.stdout:
   ...  # Fine

如果您需要双向通信,请使用通信

于 2009-08-14T13:57:35.347 回答
6

这两个答案很好地抓住了问题的要点:不要混合向子进程写入内容、从中读取内容、再次写入等等——管道的缓冲意味着你有死锁的风险。如果可以的话,首先将您需要写入子进程的所有内容写入子进程,关闭该管道,然后再读取子进程必须说的所有内容;communicate如果数据量不是太大而无法放入内存(如果是,您仍然可以“手动”实现相同的效果)。

如果您需要更细粒度的交互,请查看pexpect,或者,如果您使用的是 Windows,请查看 wexpect

于 2009-08-14T14:38:51.783 回答
4

如果您的子流程有少量到中等数量的输出,SilentGhost/chrispy 的答案是可以的。但是,有时可能会有很多输出——太多了,无法舒适地在内存中缓冲。在这种情况下,要做的是start()进程,并产生几个线程 - 一个用于读取child.stdout,一个用于读取子进程child.stderr在哪里。child然后,您需要wait()终止子进程。

这实际上是如何communicate()工作的;使用自己的线程的优点是您可以在生成子进程的输出时对其进行处理。例如,在我的项目中,python-gnupg我使用这种技术在生成 GnuPG 可执行文件时读取状态输出,而不是通过调用communicate(). 欢迎您查看该项目的源代码 - 相关内容在模块中gnupg.py

于 2009-08-14T14:33:29.670 回答
0

data_stream.stdout是标准输出句柄。你不应该循环它。communicate返回 的元组(stdoutdata, stderr)。你stdoutdata应该用它来做你的事情。

于 2009-08-14T13:54:15.570 回答