1

请看下面的例子:`apply_async`沉默“共享队列错误”

from multiprocessing import Queue, Pool 

def work(*args): 
    print('work') 
    return 0 

if __name__ == '__main__': 
    queue = Queue() 
    pool = Pool(1) 
    result = pool.apply_async(work, args=(queue,)) 
    print(result.get()) 

这引发了以下RuntimeError

Traceback (most recent call last): 
    File "/tmp/test.py", line 11, in <module> 
    print(result.get()) 
    [...] 
RuntimeError: Queue objects should only be shared between processes through inheritance 

但有趣的例外才升起,当我尝试get的结果,而不是当“分享”发生时。当我实际上确实共享队列(并且work永远不会执行!)时,评论相应的线路将使错误消失。

所以这里去我的问题:为什么当请求的结果是这样的例外,只是提出,而不是当即使错误似乎是公认的,因为目标work功能从来没有所谓的apply_async方法被调用?

看起来异常发生在不同的进程中,并且只能在进程间通信以请求结果的形式执行时才可用于主进程。然而,然而,我想知道为什么在调度到另一个过程之前不执行这种检查
(如果我用在两个work队列和主处理用于通信那么这将(静默)引入死锁。)


Python版本是3.5.2。


我已经阅读了以下问题:

回答

0

此行为来自multiprocessing.Pool的设计。

在内部,当您致电apply_async时,您将您的工作放在Pool调用队列中,然后取回一个AsyncResult对象,它允许您使用get检索计算结果。 另一个线程然后负责酸洗你的工作。在这个线程中,发生了RuntimeError,但您已经从呼叫中返回async_apply。因此,它会将结果设置为AsyncResult作为例外,当您致电get时会引发该结果。

该行为使用某种未来的结果,当您尝试使用concurrent.futures,其中有未来明确的对象和,海事组织,更好的设计,以处理故障比较好理解,有可以查询失败的未来对象,而不调用get功能。

+0

谢谢你的回答!但我有个问题。如果'Queue'对象不能通过参数在进程之间共享,为什么我们可以通过'multiprocessing'完成这个操作。Process'对象(参见[本文档示例 - > Queues](https://docs.python.org/3/library/multiprocessing.html#exchanging-objects-between-processes))?这不会引发'RuntimeError'并且工作正常,所以区别在哪里?参数必须转移到其他进程中,就像“Pool”一样。酸洗在这里呢? –

+0

在'Pool'中,当你实例化时,这个过程就会产生。因此,当你调用'apply_async'时,'Process'已经启动。你可以使用'initializer'和'initargs'参数在'Pool'中传递'Queue'来在我认为的子进程中声明一个全局的'Queue'。 –

+0

您也可以将'Queue'声明为模块的全局属性,以避免混淆'initializer'。 'pickle'应该能够处理我认为的这种情况。 –