我有一个程序使用多处理库来计算一些东西。大约有10K输入要计算,每个输入需要0.2秒到10秒。
我目前的做法是使用游泳池:
# Inputs
signals = [list(s) for s in itertools.combinations_with_replacement(possible_inputs, 3)]
# Compute
with mp.Pool(processes = N) as p:
p.starmap(compute_solutions, [(s, t0, tf, folder) for s in signals])
print (" | Computation done.")
我注意到在要检查的300/400最后输入上,程序变慢了很多。我的问题是:Pool
和starmap()
的行为如何?
根据我的观察,我相信如果我得到10K输入和N = 4
(4个过程),则将2 500个第一个输入分配给第一个过程,2 500个分配给第二个过程,......并且每个过程以连续方式处理其输入。
这意味着如果某些进程在其他进程之前清除了Queue,则它们不会执行新的任务。
这是正确的吗?
如果这是正确的,我怎样才能拥有一个可以用这个伪代码表示的更智能的系统:
workers = Initialize N workers
tasks = A list of the tasks to perform
for task in tasks:
if a worker is free:
submit task to this worker
else:
wait
感谢您的帮助:)
N.B:不同的地图功能有什么区别。我相信map()
,imap_unordered()
,imap
,starmap
存在。
它们之间有什么区别?我们何时应该使用其中一种?
答案 0 :(得分:1)
这意味着如果某些进程在其他进程之前清除了Queue,则它们不会执行新的任务。
这是正确的吗?
没有。 multiprocess.Pool()
的主要目的是将传递的工作负载分散到其工作池中 - 这就是为什么它带有所有这些映射选项 - 其各种方法之间的唯一区别在于工作负载的实际工作方式分配以及如何收集所得到的回报。
在您的情况下,您使用[(s, t0, tf, folder) for s in signals]
生成的可迭代将具有发送给下一个免费工作者的每个元素(最终取决于signals
大小)(调用为{池中的{1}}),一次一个(如果传递compute_solutions(s, t0, tf, folder)
参数,则更多),直到整个迭代用尽。你无法控制哪个工人执行哪个部分,等等。
工作负载也可能无法均匀分布 - 一个工作人员可能会根据资源使用情况,执行速度,各种内部事件处理更多的条目...
但是,使用chunksize
的{{1}},map
和imap
方法,您可以获得均匀有序传播的幻觉,因为它们会在内部同步每个工作人员的回报匹配 source iterable(即结果的第一个元素将包含来自被调用函数的结果返回与iterable的第一个元素)。如果您想查看下面实际发生的情况,可以尝试这些方法的异步/无序版本。
因此,默认情况下,您会获得更智能的系统,但如果您希望完全控制工作池,则可以始终使用multiprocessing.Pool.apply_async()
。
作为旁注,如果您正在寻找优化对迭代本身的访问权限(因为池映射选项将消耗它的很大一部分),您可以检查{{3 }}
最后,
它们之间有什么区别?我们何时应该使用其中一种?
而不是我在这里引用,请转到this answer,因为对这些之间的区别有很好的解释。