如何在多处理中访问过程安全的容器.Pool

时间:2015-06-09 17:11:08

标签: python multiprocessing

我有以下设置:

import multiprocessing
def heavy_work(args):
    queue, data, idx = args
    state = 0
    for elem in queue:
        #  decide how to process current data point, store collected information in 'state'
    else:
        queue.put(modify(data[idx], state))


def mp_heavy_work(data):
    queue = multiprocessing.Manager().Queue(len(data))
    pool = multiprocessing.Pool(processes=4)
    pool.map(heavy_work, ((queue, data, i) for i in range(len(data))))

问题是,队列不可迭代,因此第5行不起作用。我需要知道如何修改以前的数据点以便决定新的数据点,因此读取write-access共享容器(当前为queue)是必要的。我想依靠一个原始的'进程安全类型而不是锁,因为主要工作是在循环内部完成的 - 所以每次进程进入时锁定它都会使多处理变得多余。

有办法吗?

1 个答案:

答案 0 :(得分:0)

为什么需要它可迭代?您可以使用普通queue.get()

try:
    while True:
        elem = queue.get(False)
        # do stuff with elem
except Queue.Empty:
    queue.put(modify(data[idx], state))

如果你真的想要一个可迭代的,你可以包装你的队列对象:

for elem in iter(queue.get, 'sentinal'):
    # do stuff
else:
    # do more stuff

这将在每次迭代时调用queue.get,直到它到达“sentianal”对象,然后它将StopIteration。这样您就可以手动关闭队列。

如果要在队列为空时执行else阻止(不手动结束迭代),则必须依赖Queue.Empty异常:

try:
    for elem in iter(lambda:queue.get(False), 'sentinal'):
        # do stuff        
except Queue.Empty:
    # do else stuff

您甚至可以将它包装在您自己的自定义包装器中:

def wrap(queue):
    try:
        for elem in iter(lambda:queue.get(False), 'sentinal'):
            yield elem
        else:
            # this is executed if the 'sentinal' is sent
            # may want to special handle this (throw custom exception?)
    except Queue.Empty:
        pass # just enter iteration

...

    for elem in wrap(queue):
        # do stuff
    else:
        # do more stuff