【问题标题】:`apply_async` silences "shared queue errors"`apply_async` 使“共享队列错误”静音
【发布时间】:2017-07-19 00:50:11
【问题描述】:

考虑以下示例:

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!)。

所以我的问题来了:为什么这个异常只在请求结果时引发,而不是在调用 apply_async 方法时引发,即使错误似乎被识别为目标 @ 987654332@函数从未被调用?

看起来异常发生在不同的进程中,只有在以请求结果的形式进行进程间通信时才能使主进程可用。但是,然后,我想知道为什么在调度到其他进程之前不执行此类检查。
(如果我在work 和主进程中都使用队列进行通信,那么这会(默默地)引入死锁。)


Python 版本是 3.5.2。


我已阅读以下问题:

【问题讨论】:

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


    【解决方案1】:

    此行为源于multiprocessing.Pool 的设计。

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

    当您尝试使用 concurrent.futures 时,可以更好地理解这种使用某种未来结果的行为,它具有明确的未来对象,而且 IMO 是一种更好的处理失败的设计,您是否可以在不调用未来对象的情况下查询未来对象是否失败get函数。

    【讨论】:

    • 感谢您的回答!但我有个问题。如果Queue 对象不能通过参数在进程之间共享,为什么我们允许使用multiprocessing.Process 对象来做到这一点(参见this documentation example -> Queues)?这不会引发RuntimeError 并且工作正常,那么区别在哪里?参数也必须转移到另一个进程,Pool 就是这种情况。这里腌制怎么样?
    • Pool 中,该进程在您实例化时生成。因此,当您调用apply_async 时,Process 已经启动。您可以使用参数initializerinitargsPool 中传递Queue,以在我认为的子进程中声明全局Queue
    • 您还可以将Queue 声明为模块的全局属性,以避免与initializer 混淆。我认为pickle 应该能够处理这种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    • 2013-11-18
    • 1970-01-01
    • 2013-04-22
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    相关资源
    最近更新 更多