多处理模块中 Pool 对象和 Manager 对象之间的位置

the position between Pool object and Manager object in multiprocessing module

 1 from multiprocessing import Pool, Manager
 2 
 3 
 4 def test(num):
 5     queue.put(num)
 6 
 7 
 8 queue = Manager().Queue()
 9 pool = Pool(5)
 10 
 11 for i in range(30):
 12     pool.apply_async(test, (i, ))
 13     
 14 pool.close()
 15 pool.join()
 16 
 17 print(queue.qsize())

上面代码的输出是30。但是,如果第8行和第9行交换(见下面的代码),输出将是0。有没有人知道为什么?谢谢!

1 from multiprocessing import Pool, Manager
2 
3 
4 def test(num):
5     queue.put(num)
6 
7 
8 pool = Pool(5)
9 queue = Manager().Queue()
10 
11 for i in range(30):
12     pool.apply_async(test, (i, ))
13     
14 pool.close()
15 pool.join()
16 
17 print(queue.qsize())

from multiprocessing import Process, Queue 


def test():
    queue.put(1)


p = Process(target=test) 
queue = Queue()
p.start()
p.join()

print(queue.qsize())

输出为1,表示子进程将号码放入父进程创建的队列中。对吗?

我假设您使用的是基于 Unix 的操作系统,就像在 NT 操作系统上一样,您的逻辑很可能会崩溃。

要了解发生了什么,我们需要深入研究 multiprocessing 内部结构。在 Unix 上,当创建一个新进程时,使用 fork 原语。当进程分叉时,parent 继续执行并且 child 作为 parent.

的精确副本启动

Python 倾向于在 multiprocessing 模块中隐藏很多东西(我特别不喜欢那样)并导致很多误解。在您的逻辑中,fork 在您创建 Pool 时发生(第一个示例中的第 9 行,第二个示例中的第 8 行)。

在第一个示例中,children 继承了 parent 创建的 queue object。因此,当他们共享同一个频道时,他们成功地进行了沟通。

在第二个中,parent 和 children 创建了他们自己的完全独立的 queue objects。当 child 将一个元素放入 queue 时,它会将其放入自己的元素中,不被任何人共享。

在第三个也是最后一个示例中,您创建了一个 Process object,然后是一个 Queue,然后您在该过程中调用了 start。猜猜 fork 什么时候发生?当您调用 start 而不是当您创建 Process object 时。这就是 queue 成功共享的原因。当我说 multiprocessing API 有点误导时,这就是我的意思。