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

时间:2018-07-18 09:45:01

标签: python python-3.x queue multiprocessing pool

 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,这意味着子进程将数字放入父进程创建的队列中。正确吗?

1 个答案:

答案 0 :(得分:1)

我假设您使用的是基于Unix的操作系统,因为在NT上您的逻辑很可能会中断。

要了解会发生什么,我们需要深入研究multiprocessing内部。在Unix上,创建新进程时,将使用fork原语。分叉时,父进程继续执行,子进程作为父进程的精确副本启动。

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

在第一个示例中,子级继承父级创建的相同queue对象。因此,由于他们共享同一频道,因此他们成功地进行了通信。

在第二个示例中,父级和子级创建了自己独立的queue对象,它们是完全独立的。当孩子将元素放在queue中时,它会将它放在自己的元素中,任何人都不会共享。

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