[英]How to use multiprocessing.Pool async without callbacks?
所以,我有一个问题,我认为必须是常见的:
我想将脚本与multiprocessing.Pool
并行化,将输入交给池,让它并行处理它们,并在父进程中接收输出。
apply_async()
看起来最适合我想做的事情。 但我不能只给出一个回调函数,因为最后我想将所有结果打印到一个文件中。 我认为将一个回调打印到单个文件句柄会导致混乱的结果(甚至不能确定我可以在这样的进程之间传递文件句柄)。
那么如何向Pool
提交输入,然后接收输出并在主进程中处理它们的最佳方法是什么? 目前我只是在列表中收集AsyncResult
对象并定期迭代它,在每个上调用.get()
方法。
我将在回应评论时澄清我的问题的一些参数:
@martineau和@Juggernaut:不是“混乱”,我的意思是我真的想保留输入的顺序,以便输出顺序相同。
@RolandSmith和@martineau:我的主要过程就是从文件读取输入,将它们交给池,然后打印结果。 我可以调用.apply()
,但是然后主进程在它继续之前等待函数完成。 我正在使用multiprocessing
来获得并行化的好处并同时处理许多输入。
为了回答你的问题,我不认为你可以在没有回调的情况下做你想做的事。
您希望异步计算结果,但是以与输入相同的顺序打印。 这意味着不仅必须等到所有输入在打印之前都被处理,而且还要知道它们在输入中的相对位置,以便在输出它们之前将它们排序回该顺序。
因此,这里是如何与一个做到这一点。 正如我之前所说,稍微棘手的部分是结果必须包含指示输入的相应位置的东西,因此结果可以在打印之前以类似的顺序排序。 由于该要求,脚本必须等到所有输入都已处理完毕。
请注意,尽管如此,您还是可以获得并行处理的好处,因为并发处理会创建单个结果本身。
import multiprocessing as mp
from random import randint
from time import sleep
def my_func(*args):
print('my_func:', args)
index, x = args
sleep(randint(1, 3)) # Take a varying amount of time to finish.
return index, x*x # Return result index and value.
if __name__ == '__main__':
result_list = []
def errorhandler(exc):
print('Exception:', exc)
def log_result(result):
# This is called whenever my_func() returns a result.
# result_list is modified only by the main process, not the pool workers.
result_list.append(result)
pool = mp.Pool()
for i in range(10):
pool.apply_async(my_func, args=(i, i*2), callback=log_result,
error_callback=errorhandler)
pool.close()
pool.join() # Wait for all subprocesses to finish.
print('result_list:', result_list)
sorted_results = [x[1] for x in sorted(result_list)]
print('sorted results:', sorted_results)
输出:
my_func: (5, 10)
my_func: (1, 2)
my_func: (4, 8)
my_func: (7, 14)
my_func: (3, 6)
my_func: (9, 18)
my_func: (0, 0)
my_func: (6, 12)
my_func: (2, 4)
my_func: (8, 16)
result_list: [(2, 16), (3, 36), (5, 100), (1, 4), (4, 64), (7, 196), (9, 324), (0, 0), (6, 144), (8, 256)]
sorted results: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
正如您在评论中所要求的,这里的代码显示了如何使用Pool.map()
而不是Pool.async()
- 这似乎更适合此问题,因为需要在进一步输出之前等待所有结果处理可以完成(例如,它需要与输入的顺序相同)。
正如您所看到的,它需要的代码要少得多 ,并且在输出结果之前不需要对结果进行排序(因此也可能更快)。
import multiprocessing as mp
from random import randint
from time import sleep
def my_func(x):
print('my_func:', x)
sleep(randint(1, 3)) # Take a varying amount of time to finish.
return x*x
if __name__ == '__main__':
input_data = range(10)
with mp.Pool(10) as pool:
result_list = pool.map(my_func, input_data) # Blocks until finished.
print('result_list:', result_list) # Will be in same order as input_data.
输出:
my_func: 3
my_func: 2
my_func: 1
my_func: 0
my_func: 8
my_func: 5
my_func: 7
my_func: 6
my_func: 4
my_func: 9
result_list: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我认为将它打印到单个文件句柄的回调将导致结果混乱
解决方案是使用结果填充回调中的Queue ,然后再获取它们。 队列是线程安全的,因此您不必担心您所谈论的混乱结果。
from queue import Queue
results = Queue()
def callback(result):
results.put(result)
后来
item = results.get()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.