为什么在与多个Popen子进程一起使用时会传递死锁?

Dav*_*son 9 python subprocess multiprocessing python-2.7

Python 2.7.3 中不会发生以下问题.但是,它在我的机器上运行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")
Run Code Online (Sandbox Code Playgroud)

如果我将进程数更改为for _ in range(1),则输出与预期一致:

('hello world\n', '')
Run Code Online (Sandbox Code Playgroud)

但是,当有两个进程(for _ in range(2))时,进程将无限期地阻塞.我尝试过手动写入stdin的替代方法:

for p in processes:
    p.stdin.write("hello world\ngoodbye world\n")
Run Code Online (Sandbox Code Playgroud)

但是,任何从进程中读取的尝试(p.stdout.read()例如)仍然是死锁.

起初似乎是相关的,但是它指定它在使用多个线程时发生,并且死锁仅在很少发生(在这里总是发生).有什么方法可以让它在2.7.3之前的Python版本上运行吗?

Joh*_*zen 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)]
Run Code Online (Sandbox Code Playgroud)

如果这会导致与其他文件描述符的问题,你重新使用(如果这是一个简单的例子),事实证明,你可以等待()/与创建它们以相反的顺序子进程通信(),它似乎上班.

即,而不是:

for p in processes:
    print p.communicate("hello world\ngoodbye world\n")
Run Code Online (Sandbox Code Playgroud)

使用:

while processes:
    print processes.pop().communicate("hello world\ngoodbye world\n")
Run Code Online (Sandbox Code Playgroud)

(或者,我想,只需在现有循环之前执行'processes.reverse()'.)