在Python 2.7.3中不会发生以下问题。但是,它在我的机器(64位Mac OSX 10.7.3)上同时出现在Python 2.7.1和Python 2.6中。这是我最终将要分发的代码,所以我想知道是否有什么方法可以完成此任务,而该方法并不太依赖于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版本上运行?
最佳答案
我不得不为此做一点挖掘。 (我曾经遇到过类似的问题,所以以为我知道答案了,但是错了。)
问题(和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()/communicate()。去工作。
即,代替:
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()”即可。)
关于python - 与多个Popen子进程一起使用时,为什么会出现死锁?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14615462/