2024-04-20 08:23:43 发布
网友
我有一些使用子流程模块运行的命令。然后我想循环输出的行。文档中说不要执行data_stream.stdout.read,我不是,但我可能正在执行调用它的操作。我循环输出如下:
for line in data_stream.stdout: #do stuff here . . .
这会导致死锁,比如从data_stream.stdout读取数据,还是为这种循环设置了Popen模块,以便它使用通信代码,但为您处理所有的调用?
这两个答案很好地抓住了问题的要点:不要将向子流程写入内容、从子流程读取内容、再次写入内容等混合在一起--管道的缓冲意味着您有陷入死锁的风险。如果可以,请先将需要写入的所有内容写入子流程,关闭该管道,然后再读取子流程必须说明的所有内容;communicate对于此目的很好,如果数据量不太大,无法放入内存(如果是,仍然可以“手动”实现相同的效果)。
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()才能终止子进程。
start()
child.stdout
child.stderr
child
wait()
这实际上就是communicate()的工作方式;使用自己的线程的优点是,可以在生成子进程的输出时对其进行处理。例如,在我的项目^{}中,我使用此技术在生成GnuPG可执行文件时读取其状态输出,而不是通过调用communicate()来等待所有输出。欢迎您检查此项目的源代码-相关内容在模块gnupg.py中。
communicate()
gnupg.py
这两个答案很好地抓住了问题的要点:不要将向子流程写入内容、从子流程读取内容、再次写入内容等混合在一起--管道的缓冲意味着您有陷入死锁的风险。如果可以,请先将需要写入的所有内容写入子流程,关闭该管道,然后再读取子流程必须说明的所有内容;
communicate
对于此目的很好,如果数据量不太大,无法放入内存(如果是,仍然可以“手动”实现相同的效果)。如果您需要更精细的交互,请查看pexpect,或者,如果您是在Windows上,wexpect。
如果要与子进程通信,即要向stdin写入数据,还要从stdout读取数据,则必须担心死锁。因为这些管道可能会被缓存,所以执行这种双向通信在很大程度上是一个禁忌:
但是,如果在构造数据流时未设置stdin(或stderr),则应该可以。
如果需要双向通信,请使用communicate。
如果您的子流程有少量到中等数量的输出,那么silenghost/chrispy的答案是可以的。不过,有时可能会有很多输出—太多,无法在内存中轻松缓冲。在这种情况下,要做的事情是
start()
进程,并生成两个线程-一个用于读取child.stdout
,一个用于读取child.stderr
,其中child
是子进程。然后需要wait()
才能终止子进程。这实际上就是} 中,我使用此技术在生成GnuPG可执行文件时读取其状态输出,而不是通过调用
communicate()
的工作方式;使用自己的线程的优点是,可以在生成子进程的输出时对其进行处理。例如,在我的项目^{communicate()
来等待所有输出。欢迎您检查此项目的源代码-相关内容在模块gnupg.py
中。相关问题 更多 >
编程相关推荐