Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python并发:使用apply_async()时挂起_Python_Concurrency_Multiprocessing_Message Queue_Pool - Fatal编程技术网

Python并发:使用apply_async()时挂起

Python并发:使用apply_async()时挂起,python,concurrency,multiprocessing,message-queue,pool,Python,Concurrency,Multiprocessing,Message Queue,Pool,我试图学习Python并发性。作为一个实验,我有一个使用进程池并通过apply_async()调用worker的程序。为了在进程(工作和结果)之间共享信息,我使用multiprocessing.Manager()中的队列 但是,当工作队列中的所有项都已处理完毕时,此代码会挂起,我不知道为什么。我必须运行程序几次来观察行为 顺便说一句,我可以正确地做到这一点:我发现了一些设计模式,人们有时称之为“毒丸”方法,而且似乎很有效。(在我的worker()方法中,当我的工作队列包含一个sentinel值时

我试图学习Python并发性。作为一个实验,我有一个使用进程池并通过apply_async()调用worker的程序。为了在进程(工作和结果)之间共享信息,我使用multiprocessing.Manager()中的队列

但是,当工作队列中的所有项都已处理完毕时,此代码会挂起,我不知道为什么。我必须运行程序几次来观察行为

顺便说一句,我可以正确地做到这一点:我发现了一些设计模式,人们有时称之为“毒丸”方法,而且似乎很有效。(在我的worker()方法中,当我的工作队列包含一个sentinel值时,我会进入一个无限循环并跳出该循环。我在工作队列上创建的sentinel值与我正在运行的进程的数量相同)

但我仍然有兴趣找出这段代码挂起的原因。 我得到如下输出(进程ID在括号中):

(程序挂起在最后一行。另一个进程5886似乎没有完成。)


谢谢您的帮助。

您遇到了比赛条件-流程
5886
看到
池中有一个项目:

[5886] worker() still running because work_queue has size 1
因此,它循环回阻塞
get
调用:

while not work_queue.empty(): # It sees it's not emtpy here
    item = work_queue.get()   # But there's no item left by the time it gets here!
但是,在调用
work\u queue.empty()
,但在调用
work\u queue.get()
之前,另一个工作进程(
5885
)使用队列中的最后一项:

[5885] processed work item 19  
[5885] worker() still running because work_queue has size 0  
[5885] worker() is finished; returning results of size 20  
所以现在
5886
将在
get
上永久阻塞。通常,如果一个队列有多个使用者,您不应该使用
empty()
方法来决定是否进行阻塞
get()
调用,因为它容易受到这种竞争条件的影响。使用您提到的“毒药丸”/“哨兵”方法是处理此场景的正确方法,或者使用非阻塞的
get
调用,并捕获发生的
Empty
异常:

try:
    item = work_queue.get_nowait()
    print "[%d] processed work item %s" % (os.getpid(), item)  
    s = '[%d] has processed %s.' % (os.getpid(), item)
    results_queue.put(s)
    work_queue.task_done()
    print "[%d] worker() still running because work_queue has size %d" % (os.getpid(), work_queue.qsize())
except Queue.Empty:
    print "[%d] worker() is finished; returning results of size %d" % (os.getpid(), results_queue.qsize())
请注意,只有当您知道一旦工作人员开始使用队列,队列的大小就不会增加时,才可以使用这种方法。否则,您可以决定当仍有更多项目要添加到队列时,工作进程应该退出

[5885] processed work item 19  
[5885] worker() still running because work_queue has size 0  
[5885] worker() is finished; returning results of size 20  
try:
    item = work_queue.get_nowait()
    print "[%d] processed work item %s" % (os.getpid(), item)  
    s = '[%d] has processed %s.' % (os.getpid(), item)
    results_queue.put(s)
    work_queue.task_done()
    print "[%d] worker() still running because work_queue has size %d" % (os.getpid(), work_queue.qsize())
except Queue.Empty:
    print "[%d] worker() is finished; returning results of size %d" % (os.getpid(), results_queue.qsize())