在多个进程之间共享结果队列


92

multiprocessing模块的文档显示了如何将队列传递给以开头的进程multiprocessing.Process。但是,如何与开始的异步工作进程共享队列apply_async?我不需要动态加入或其他任何方法,而只是工人(反复)将其结果报告给基地的一种方法。

import multiprocessing
def worker(name, que):
    que.put("%d is done" % name)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)
    q = multiprocessing.Queue()
    workers = pool.apply_async(worker, (33, q))

失败的原因是: RuntimeError: Queue objects should only be shared between processes through inheritance。我理解这意味着什么,并且我理解继承的建议,而不是要求进行酸洗/取消酸洗(以及所有Windows特殊限制)。但如何我通过队列的方式,作品?我找不到一个示例,并且我尝试了多种失败的替代方法。请帮助?

Answers:


133

尝试使用multiprocessing.Manager来管理您的队列,并使其他工作人员也可以访问它。

import multiprocessing
def worker(name, que):
    que.put("%d is done" % name)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)
    m = multiprocessing.Manager()
    q = m.Queue()
    workers = pool.apply_async(worker, (33, q))

做到了,谢谢!我的原始代码中的异步调用存在一个不相关的问题,因此我也将修复程序复制到了您的答案中。
亚历克西斯

16
有什么解释为什么queue.Queue()不适合这个?
mrgloom

@mrgloom:queue.Queue是使用内存中的锁用于线程化的。在多进程环境中,queue.Queue()由于子进程不共享内存(大部分情况下),因此每个子进程将在其自己的内存空间中获得实例的副本。
LeoRochael

@alexis在多个工作程序向其中插入数据之后,如何从Manager()。Queue()中获取元素?
MSS

10

multiprocessing.Pool已经具有共享的结果队列,则无需另外包含Manager.QueueManager.Queue是一个queue.Queue位于后台的(多线程队列),位于单独的服务器进程上,并通过代理公开。与Pool的内部队列相比,这增加了额外的开销。与依赖Pool的本机结果处理相反,Manager.Queue也不能保证对结果进行排序。

工作进程不是从开始的.apply_async(),在实例化时已经发生Pool。什么当你调用开始pool.apply_async()一个新的“工作”。Pool的工作进程在multiprocessing.pool.worker后台运行-function。此函数负责处理通过Pool内部传输的新“任务”,Pool._inqueue并通过将结果发送回父级Pool._outqueue。您指定的func将在内执行multiprocessing.pool.workerfunc只需要return做某事,结果将自动发送回父级。

.apply_async() 立即(异步)返回一个AsyncResult对象(的别名ApplyResult)。您需要.get()在该对象上调用(正在阻止)以接收实际结果。另一种选择是注册一个回调函数,一旦结果准备就绪,就会触发该回调函数。

from multiprocessing import Pool

def busy_foo(i):
    """Dummy function simulating cpu-bound work."""
    for _ in range(int(10e6)):  # do stuff
        pass
    return i

if __name__ == '__main__':

    with Pool(4) as pool:
        print(pool._outqueue)  # DEMO
        results = [pool.apply_async(busy_foo, (i,)) for i in range(10)]
        # `.apply_async()` immediately returns AsyncResult (ApplyResult) object
        print(results[0])  # DEMO
        results = [res.get() for res in results]
        print(f'result: {results}')       

示例输出:

<multiprocessing.queues.SimpleQueue object at 0x7fa124fd67f0>
<multiprocessing.pool.ApplyResult object at 0x7fa12586da20>
result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

注意:为指定timeout-parameter .get()不会停止在worker中执行任务的实际处理,只会通过引发来解除对等待的父对象的阻塞multiprocessing.TimeoutError


有趣的是,我会第一时间尝试一下。在2012
。– Alexis

@alexis Python 2.7(2010)此处仅缺少上下文管理器和的error_callback-parameter apply_async,因此此后并没有太大变化。
Darkonaut
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.