如何在多处理中使用队列设置管道

时间:2013-06-25 18:45:36

标签: python multiprocessing

这是我的代码,它应该做的事与this other question尝试做的非常相似,特别是这个图是相关的:Process Diagram f1 =产生,f2 = f3 =工人,f4 =消费者。

我还没有尝试过很好地结束一切的问题,这不是这个问题的内容。我收到错误“RuntimeError:队列对象只应通过继承在进程之间共享” 我不知道该怎么做才能解决它。我只是想把队列传递给Go的频道,真的。这是代码。

import multiprocessing


def produce(n, queue):
    for i in xrange(n):
        queue.put(i)

def worker(in_queue, out_queue):
    for i in iter( in_queue.get, None):
        out_queue.put(i*i)

def consumer(queue):
    ans = []
    for i in iter( queue.get, None):
        ans.append(i)
    return ans


def main(n):
    pool = multiprocessing.Pool(4)
    in_queue = multiprocessing.Queue()
    out_queue = multiprocessing.Queue()

    pool.apply_async(produce, (n, in_queue))
    for i in range(2):
        pool.apply_async(worker, (in_queue, out_queue))
    result = consumer(out_queue)
    pool.close()
    pool.join()
    return result

main(200)

我该如何修复它?

有更简单的方法吗?

我已经尝试Pool.map,但我想让它发挥作用。

2 个答案:

答案 0 :(得分:2)

multiprocessing.Pool已经设置了必要的IPC机制,允许您在工作启动后向其工作人员提交作业,但您不能在以后作为参数传递ist a Queue或类似工具。这就是你的代码不起作用的原因。在启动子进程时,它必须知道如何与其父进程通信。

因此,如果您需要设置自己的队列,则应直接使用multiprocessing.Process。此外,你所写的是典型的工人,他们在一个循环中等待新工作并处理它们。在工人池中运行这样的工人不是你想要做的事情。

这样你的代码就可以了:

import multiprocessing


def produce(n, queue):
    for i in xrange(n):
        queue.put(i)

def worker(in_queue, out_queue):
    for i in iter( in_queue.get, None):
        out_queue.put(i*i)

def consumer(queue):
    ans = []
    for i in iter( queue.get, None):
        print(i)
        ans.append(i)
    return ans


def main(n):
    in_queue = multiprocessing.Queue()
    out_queue = multiprocessing.Queue()
    producer = multiprocessing.Process(target=produce, args=(n, in_queue))
    for i in range(2):
        w = multiprocessing.Process(target=worker, args=(in_queue, out_queue))
        w.start()
    producer.start()
    res = consumer(out_queue)

main(200)

我在consumer中添加了一个打印声明,表明发生了一些事情。 consumer函数永远不会终止,因为你从队列中读取的代码会等待一个永远不会出现的终止None,因为工作者和生产者都没有把它放入队列......

答案 1 :(得分:0)

使用multiprocessing.Manager可以跨池化进程共享队列。我更新了OP的代码以使用pool.apply_async方法。为此,我使用None来指示进程方法中的任务完成,并添加代码以等待main方法中异步调用的完成。

import multiprocessing

def produce(n, queue):
    for i in xrange(n):
        queue.put(i)
    # None indicates termination / completion
    queue.put(None)

def worker(in_queue, out_queue):
    while True:
        i = in_queue.get()
        if i is None:
            # Put the None back for other workers listening to the queue to see
            in_queue.put(None)
            out_queue.put(None)
            return
        out_queue.put(i*i)

def consumer(queue):
    ans = []
    while True:
        i = queue.get()
        if i is None:
            queue.put(None)
            return ans
        ans.append(i)

def main(n):
    manager = multiprocessing.Manager()
    in_queue = manager.Queue()
    out_queue = manager.Queue()

    pool = multiprocessing.Pool(4)

    async_results = []
    ar = pool.apply_async(produce, (n, in_queue))
    async_results.append(ar)
    for i in range(2):
        ar = pool.apply_async(worker, (in_queue, out_queue))
        async_results.append(ar)
    ar = pool.apply_async(consumer, (out_queue,))
    async_results.append(ar)

    for ar in async_results:
        ar.wait()

    result = async_results[len(async_results)-1].get()
    print(result)

    pool.close()
    pool.join()
    return result

if __name__ == "__main__":
    main(200)