以下问题在Python 2.7.3中发生 not 。但是,它在我的机器上运行Python 2.7.1和Python 2.6(64位Mac OSX 10.7.3)。这是我最终将分发的代码,所以我想知道是否有任何方法可以完成此任务,而不是如此显着地依赖于Python版本。
我需要并行打开多个子进程并将STDIN数据写入每个子进程。通常我会使用Popen.communicate
方法执行此操作。但是,只要我同时打开多个进程,communicate
就会死锁。
import subprocess
cmd = ["grep", "hello"]
processes = [subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
for _ in range(2)]
for p in processes:
print p.communicate("hello world\ngoodbye world\n")
如果我将进程数更改为for _ in range(1)
,则输出与预期一致:
('hello world\n', '')
但是,当有两个进程(for _ in range(2)
)时,进程将无限期地阻塞。我已经尝试过手动写入stdin的替代方法:
for p in processes:
p.stdin.write("hello world\ngoodbye world\n")
但是,任何从进程中读取的尝试(例如p.stdout.read()
)仍然会死锁。
起初this似乎是相关的,但是它指定它在使用多个线程时发生,并且死锁仅在很少发生(在这里总是发生)。有没有办法让这个在2.7.3之前的Python版本上运行?
答案 0 :(得分:9)
我不得不为这一点挖掘一下。 (我曾经遇到过类似的问题,所以我觉得我知道答案,但错了。)
此处描述了问题(以及2.7.3的补丁):
http://bugs.python.org/issue12786
问题是PIPE是由子进程继承的。答案是在Popen调用中使用'close_fds = True'。
processes = [subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,close_fds=True)
for _ in range(2)]
如果这导致其他文件描述符的问题,你想要重用(如果这是一个简化的例子),事实证明你可以用子进程wait()/ communic()他们创建的顺序相反,似乎有效。
即代替:
for p in processes:
print p.communicate("hello world\ngoodbye world\n")
使用:
while processes:
print processes.pop().communicate("hello world\ngoodbye world\n")
(或者,我想,只需在现有循环之前执行'processes.reverse()'。)