使用管道在池中的工作程序之间进行通信

时间:2018-02-01 00:33:40

标签: python multiprocessing

我想使用管道在多处理池生成的工作进程之间进行通信。我试图将管道作为iterable传递到池中,但代码始终挂起。

这是挂起的代码。它非常简单,实际上甚至不使用管道(尽管它们被传递给工作者功能)。

import os
import multiprocessing as mp
from multiprocessing import Pool

def worker(d):
    j,p = d      # Notice that p (a pipe) is never used!)
    pid = os.getpid()
    msg = "Greetings from job {} ({})".format(j,pid)
    print(msg)
    return (j,pid)

# Main program
np = 4
pipes_0,pipes_1 = zip(*[mp.Pipe() for i in range(np)])
data = zip(range(np),pipes_1)  # Doesn't work (even though pipes not used)
# data = zip(range(np),range(np))  # Works

pool = Pool(processes=np)
results_async = pool.map_async(func=worker, iterable=data)
results = results_async.get()
print(results)

当管道作为zipped iterable的一部分传递时,输出通常会挂起以下输出:

Greetings from job 0 (35824)
Greetings from job 1 (35825)
(code usually hangs here....)

奇怪的是,我没有在上面的代码中使用管道,所以看起来池内的东西正在从管道中出现。

如果我不将管道作为传递给工作人员的数据的一部分,(使用data的注释定义)代码按预期工作并生成

Greetings from job 0 (35865)
Greetings from job 1 (35866)
Greetings from job 2 (35867)
Greetings from job 3 (35868)
[(0, 35865), (1, 35866), (2, 35867), (3, 35868)]

作为比较点,显式分叉进程的类似代码(使用mp.Process而不是池)在任何一种情况下都按预期工作。

实际上,这段代码使用了函数内部的管道,并且工作正常。

import os
import multiprocessing as mp

def worker(d):
    j,p = d
    pid = os.getpid()
    p.send("Greetings from job {} ({})".format(j,pid))

# Main program
np = 4
pipes_0,pipes_1 = zip(*[mp.Pipe() for i in range(np)])
data = zip(range(np),pipes_1)

jobs = []
for d in data:
    p = mp.Process(target=worker,args=[d])
    p.start()
    jobs.append(p)

for p0 in pipes_0:
    print("{:s}".format(p0.recv()))

for j in jobs:
     j.join()

print("Done")

产生预期的输出。

Greetings from job 0 (35834)
Greetings from job 1 (35835)
Greetings from job 2 (35836)
Greetings from job 3 (35837)
Done

最初,我想到了 通过显式启动进程,我很幸运能避免任何死锁,并且池使用的更复杂的执行计划在启动作业时引入了足够的延迟导致死锁。

但这并不能解释为什么池代码不起作用,即使根本没有引用管道也是如此。

我正在运行OSX 10.13.2,Python 3.6.3 | Anaconda自定义(64位)|

任何见解都会非常有用!

2 个答案:

答案 0 :(得分:1)

它和这里一样吗? Passing a Pipe/Connection as context arg to multiprocessing Pool.apply_async()

我猜你因为Mac OS而没有收到那里提到的错误信息。

链接中的答案说它是Python 2的一个错误。我在Python 3中尝试了你的代码并且它有效。

答案 1 :(得分:0)

此问题是早期2.x版本的Python中的一个错误,并且在此问题上有几篇帖子。据说,从Python 3.3开始修复了这个bug。但是,我在OSX上运行Python 3.6,我的代码挂起。

作为比较点,我运行了发布的代码here 结果很相似。在该帖子的第二个代码中,队列作为参数传递给池工作者。在Linux(Anaconda 3.5)和OSX(Anaconda 3.6)上,该代码对我来说很重要。

奇怪的是,我的代码运行在Linux版本的Anaconda上。管好,排队不好?

我开始喜欢游泳池了。