python子进程模块:在子进程的stdout上循环

2024-04-20 08:23:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些使用子流程模块运行的命令。然后我想循环输出的行。文档中说不要执行data_stream.stdout.read,我不是,但我可能正在执行调用它的操作。我循环输出如下:

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

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


Tags: 模块in文档命令forreaddatastream
3条回答

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

如果您需要更精细的交互,请查看pexpect,或者,如果您是在Windows上,wexpect

如果要与子进程通信,即要向stdin写入数据,还要从stdout读取数据,则必须担心死锁。因为这些管道可能会被缓存,所以执行这种双向通信在很大程度上是一个禁忌:

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

但是,如果在构造数据流时未设置stdin(或stderr),则应该可以。

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

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

如果您的子流程有少量到中等数量的输出,那么silenghost/chrispy的答案是可以的。不过,有时可能会有很多输出—太多,无法在内存中轻松缓冲。在这种情况下,要做的事情是start()进程,并生成两个线程-一个用于读取child.stdout,一个用于读取child.stderr,其中child是子进程。然后需要wait()才能终止子进程。

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

相关问题 更多 >