python - 为什么与多个 Popen 子进程一起使用时会发生通信死锁?

标签 python python-2.7 multiprocessing subprocess

以下问题不会出现在 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)),进程会无限期地阻塞。我尝试了手动写入标准输入的替代方法:

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/

相关文章:

python - 当 py.test 测试失败时,PyCharm 可以进入调试吗

python - 将 MySQL 数据库连接到 Google Assistant 的可能性

python - python 2.7的内存库

python - 在 Windows 上使用适用于 Python 2 的 pip 安装requirements.txt

python - 有没有更快的方法来搜索 numpy 数组

python - 用 str、float、int 和元组除法

Python 运行 ffmpeg 并进行多处理

每个子进程的 python并发.futures ProcessPoolExcutor 任务

python multiprocessing - 重新运行初始化程序,或在所有工作人员上运行函数?

python - 如何在 Django 中获取整个当前 URL