当参数包含队列时,如何将特定于工作者的初始化参数传递给工作池?

时间:2017-01-02 22:17:51

标签: python queue multiprocessing

我有兴趣使用the_pool使用multiprocessing.Pool进行通信来实例化一组工作人员Queue。但是,每个worker都有一个参数role,该参数对于该worker是唯一的,需要在worker初始化期间提供。这种约束是由我与之接口的API强加的,因此无法解决。如果我不需要队列,我可以迭代一个role值列表并调用apply_async,如下所示:

[the_pool.apply_async(worker_main, role) for role in roles]

不幸的是,Queue对象只能在池实例化期间传递给池,如:

the_pool = multiprocessing.Pool(3, worker_main, (the_queue,))

尝试通过Queue的参数传递apply_async会导致运行时错误。在以下示例中,从this question改编,我们尝试实例化三个工作池。但是示例失败了,因为无法从roles获取角色元素到池中的initargs

import os
import time
import multiprocessing

# A dummy function representing some fixed functionality.
def do_something(x):
    print('I got a thing:', x)

# A main function, run by our workers. (Remove role arg for working example)
def worker_main(queue, role):

    print('The worker at', os.getpid(), 'has role', role, ' and is initialized.')

    # Use role in some way. (Comment out for working example)
    do_something(role)

    while True:
        # Block until something is in the queue.
        item = queue.get(True)
        print(item)
        time.sleep(0.5)

if __name__ == '__main__':

    # Define some roles for our workers.
    roles = [1, 2, 3]

    # Instantiate a Queue for communication.
    the_queue = multiprocessing.Queue()

    # Build a Pool of workers, each running worker_main.
    # PROBLEM: Next line breaks - how do I pass one element of roles to each worker?
    the_pool = multiprocessing.Pool(3, worker_main, (the_queue,))

    # Iterate, sending data via the Queue.
    [the_queue.put('Insert useful message here') for _ in range(5)]

    worker_pool.close()
    worker_pool.join()
    time.sleep(10)

一个简单的解决方法是在Queue中包含第二个initargs,它仅用于传达每个工作者的角色,并阻止工作程序执行,直到它通过该队列接收角色。但是,这会引入一个不必要的额外队列。相关文档为here。非常感谢指导和建议。

2 个答案:

答案 0 :(得分:4)

为什么不使用两个工作器函数,一个仅用于初始化?像:

def worker_init(q):
     global queue
     queue = q

def worker_main(role):
     # use the global `queue` freely here

初始化与您展示的内容大致相同,除了调用worker_init

the_pool = multiprocessing.Pool(3, worker_init, (the_queue,))

每个工作进程只执行一次初始化,每个进程一直持续到Pool终止。要完成工作,请完成您想要做的事情:

[the_pool.apply_async(worker_main, role) for role in roles]

也没有必要传递the_queue - 每个工作进程在初始化期间都已经了解过它。

答案 1 :(得分:0)

您可以使用角色创建队列:

then