【问题标题】:Multiprocessing pool and queues多处理池和队列
【发布时间】:2016-04-18 17:42:48
【问题描述】:

我正在对池使用多处理。我需要将结构作为参数传递给必须在单独进程中使用的函数。我面临multiprocessing.Pool 的映射功能的问题,因为我既不能复制Pool.Queue,也不能复制Pool.Array。该结构将用于动态记录每个终止进程的结果。这是我的代码:

import multiprocessing
from multiprocessing import Process, Manager, Queue, Array
import itertools
import time

def do_work(number, out_queue=None):
    if out_queue is not None:
        print "Treated nb ", number
        out_queue.append("Treated nb " + str(number))
    return 0


def multi_run_wrapper(iter_values):
    return do_work(*iter_values)

def test_pool():
    # Get the max cpu
    nb_proc = multiprocessing.cpu_count()

    pool = multiprocessing.Pool(processes=nb_proc)
    total_tasks = 16
    tasks = range(total_tasks)

    out_queue= Queue()  # Use it instead of out_array and change out_queue.append() into out_queue.put() in the do_work() function.
    out_array = Array('i', total_tasks)
    iter_values = itertools.izip(tasks, itertools.repeat(out_array))
    results = pool.map_async(multi_run_wrapper, iter_values)

    pool.close()
    pool.join()
    print results._value
    while not out_queue.empty():
        print "queue: ", out_queue.get()
    print "out array: \n", out_array

if __name__ == "__main__":
    test_pool()

我需要在一个分离的进程中启动一个工作程序并将我的输出队列作为参数传递。我还想指定包含有限数量的正在运行的进程的池。为此,我正在使用 pool.map_async() 函数。不幸的是,上面的代码给了我一个错误:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 808, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 761, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 342, in _handle_tasks
    put(task)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/queues.py", line 77, in __getstate__
    assert_spawning(self)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/forking.py", line 52, in assert_spawning
    ' through inheritance' % type(self).__name__
RuntimeError: Queue objects should only be shared between processes through inheritance

我相信这是因为 Queue 永远无法复制,正如我在文档中看到的那样。 然后我想把队列变成一个全局变量,这样我就不需要再传递它了,但在我看来那会很混乱。我也想过改用multiprocessing.Array

out_array = Array('i', total_tasks)

但会出现与队列相同的错误:

# ...
RuntimeError: SynchronizedArray objects should only be shared between processes through inheritance

我需要使用此功能 - 使用多处理和交换来自子进程的信息 - 在一个相对较大的软件中,所以我希望我的代码保持干净整洁。

如何以优雅的方式将队列传递给我的工作人员?

当然,任何其他处理主要规范的方式都是受欢迎的。

【问题讨论】:

    标签: python python-2.7 multiprocessing pool


    【解决方案1】:

    multiprocessing.Pool 不会接受 multiprocessing.Queue 作为其工作队列中的参数。我相信这是因为它在内部使用队列将数据来回发送到工作进程。有几种解决方法:

    1) 你真的需要使用队列吗? Pool 函数的一个优点是它们的返回值被发送回主进程。迭代池中的返回值通常比使用单独的队列更好。这也避免了通过检查 queue.empty()

    引入的竞争条件

    2) 如果您必须使用Queue,您可以使用multiprocessing.Manager 中的一个。这是共享队列的代理,可以作为参数传递给Pool 函数。

    3) 您可以在创建Pool 时使用initializer 将普通Queue 传递给工作进程(如https://stackoverflow.com/a/3843313)。这有点hacky。

    竞态条件我上面提到的来自:

    while not out_queue.empty():
        print "queue: ", out_queue.get()
    

    当您有工作进程填充您的队列时,您可能会遇到队列当前为空的情况,因为工作人员将要向其中放入一些东西。如果您此时检查.empty(),您将提前结束。更好的方法是将 sentinal 值放入队列中,以便在您完成将数据放入队列时发出信号。

    【讨论】:

    • 您给了我不同的宝贵建议,谢谢。请放心,竞态条件被用作虚拟测试;)
    • 如果它作为 init 传递它会接受它。见here
    猜你喜欢
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    相关资源
    最近更新 更多