我正在尝试使用multiprocessing
在Python中创建一个简单的生产者/消费者模式。它有效,但它挂在poll.join()
上。
from multiprocessing import Pool, Queue
que = Queue()
def consume():
while True:
element = que.get()
if element is None:
print('break')
break
print('Consumer closing')
def produce(nr):
que.put([nr] * 1000000)
print('Producer {} closing'.format(nr))
def main():
p = Pool(5)
p.apply_async(consume)
p.map(produce, range(5))
que.put(None)
print('None')
p.close()
p.join()
if __name__ == '__main__':
main()
示例输出:
~/Python/Examples $ ./multip_prod_cons.py
Producer 1 closing
Producer 3 closing
Producer 0 closing
Producer 2 closing
Producer 4 closing
None
break
Consumer closing
然而,当我更改一行时,它可以正常工作:
que.put([nr] * 100)
在运行Python 3.4.3或Python 2.7.10的Linux系统上100%可重现。我错过了什么吗?
答案 0 :(得分:1)
这里有很多混乱。你所写的不是生产者/消费者的情景,而是混乱,滥用另一种通常被称为“工人池”的模式。
工人模式模式是生产者/消费者模式的应用程序,其中有一个生产者调度工作,许多消费者使用它。在这种模式中,Pool
的所有者最终成为生产者,而工人将成为消费者。
在您的示例中,您可以使用混合解决方案,其中一个工作人员最终成为消费者,而其他人则充当中间件。整个设计效率非常低,重复了Pool
已经提供的大部分逻辑,更重要的是,它非常容易出错。你最终遭受的是Deadlock。
将对象放入multiprocessing.Queue
是一种异步操作。仅当Queue
已满且您的Queue
具有无限大小时,它才会屏蔽。
这意味着您的produce
函数会立即返回,因此对p.map
的调用不会像您期望的那样阻塞。相关工作程序处理,等到实际消息通过Pipe
用作通信通道的Queue
。
接下来发生的事情是,当您放入Queue
None
“消息”时,您会过早终止您的消费者,该消息会在您produce
函数创建的所有列表被正确推送之前传递通过Pipe
。
您致电p.join
后会发现问题,但实际情况如下。
p.join
调用正在等待所有工作进程终止。Queue
的{{1}}。Pipe
。如果您的列表在您将终止消息实际发送到Pipe
函数之前足够小,则问题不会显示。