假设我有multiprocessing.Pool
执行的任务。如何允许此任务向执行它的Pool
添加新任务?例如,
def integers(pool, queue, n1, n2):
print ("integers(%d)" % n)
queue.put(n)
pool.apply_async(integers, (pool, queue, n+1)) # crashes; can't pickle `pool`
def start():
pool = multiprocessing.Pool()
queue = multiprocessing.Queue()
integers(pool, queue, 1)
while True:
yield queue.get()
答案 0 :(得分:1)
不可能挑选Pool
,因此如果您希望工作人员能够添加任务,您必须找到解决方法。
您可以使用特定的“sentinel”返回值告诉主程序将新任务添加到Pool
:
while True:
ret_value = queue.get()
if is_sentinel(ret_value):
pool.apply_asynch(*get_arguments(ret_value))
yield ret_value
只要返回值要求您向is_sentinel
和True
添加更多作业,Pool
返回get_arguments
是一个能够获取参数的函数传递给Pool
。
此类函数的最简单实现可能是:
def is_sentinel(value):
"""Assume only sentinel values are tuples, or sequences."""
return isinstance(value, tuple)
# or, using duck-typing
try:
len(value)
except TypeError:
return False
else:
return True
def get_arguments(value):
"""Assume that the sentinel value *is* the tuple of arguments
to pass to the Pool.
"""
return value
# or return value[1:] if you want to include a "normal" return value
传递给apply_asynch
的函数在想要添加新任务时返回tuple
(或序列) ,并且在这种情况下它不提供任何回报值。
添加提供返回值的可能性非常简单(例如:元组的第一个元素可能是“正常”返回值)。
另一种方法可能是使用工作人员可以提出请求的第二个队列。在每次迭代时,您都可以使用get_nowait()
方法查看worker是否请求在队列中添加更多作业。
使用第一种方法的示例:
def is_sentinel(value):
return isinstance(value, tuple)
def get_arguments(value):
return value
def integers(queue, n1, n2):
print("integers(%d)" % n1)
queue.put(n1)
if n1 < n2:
queue.put((integers, (queue, n1+1, n2)))
def start():
pool = multiprocessing.Pool()
queue = multiprocessing.Queue()
m = 0
n = 100
pool.apply_asynch(integers, (queue, m, n))
while True:
ret_val = queue.get()
if is_sentinel(ret_val):
pool.apply_asynch(*get_arguments(ret_val))
else:
yield ret_val
使用第二种方法的示例:
# needed for queue.Empty exception
import queue
def integers(out_queue, task_queue, n1, n2):
print("integers(%d)" % n1)
out_queue.put(n1)
if n1 < n2:
task_queue.put((n1+1, n2))
def start():
pool = multiprocessing.Pool()
out_queue = multiprocessing.Queue()
task_queue = multiprocessing.Queue()
task_queue.put((0, 100))
while True:
try:
# may be safer to use a timeout...
m, n = task_queue.get_nowait()
pool.apply_asynch(integers, (out_queue, task_queue, m, n))
except queue.Empty:
# no task to perform
pass
yield out_queue.get()