pmap 有一个 batch_size 参数,默认情况下为 1。这意味着集合的每个元素将被一个一个地发送给 可用 工作人员或要转换的任务你提供的功能。如果每个函数调用做了大量的工作,并且可能每个调用所花费的时间不同,使用pmap的好处是不让worker空闲,而其他worker都在工作,因为当一个worker完成一个转换时,它会要求下一个要转换的元素。因此,pmap 有效地平衡了工作人员/任务之间的负载。
然而,
@distributed for-loop 在开始时将给定范围在工作人员之间一次分区,不知道范围的每个分区将花费多少时间。例如,考虑一个矩阵集合,其中集合的前 100 个元素是 2×2 矩阵,接下来的 100 个元素是 1000×1000 矩阵,我们希望使用 @ 对每个矩阵求逆987654327@ for 循环和 2 个工作进程。
@sync @distributed for i = 1:200
B[i] = inv(A[i])
end
第一个工作人员将获得所有 2×2 矩阵,第二个工作人员将获得 1000×1000 矩阵。第一个工人将很快完成所有的转换并闲置,而另一个工人将继续工作很长时间。尽管您使用了 2 个工作人员,但整个工作的主要部分将在第二个工作人员上串行有效地执行,并且使用多个工作人员几乎没有任何好处。这个问题在并行计算的上下文中称为负载平衡。问题也可能出现,例如,当一个处理器速度慢而另一个处理器速度快时,即使要完成的工作是同质的。
但是,对于非常小的工作转换,使用带有小批量大小的 pmap 会产生可能很大的通信开销,因为在每个批次之后,处理器需要从调用进程中获取下一个批次,而使用 @distributed for-loops 每个工作进程在开始时都会知道它负责范围的哪一部分。
pmap 和 @distributed for 循环之间的选择取决于您想要实现的目标。如果您要像map 那样转换集合,并且每次转换都需要大量工作并且这个工作量是变化的,那么您可能会更好地选择pmap。如果每个转换都很小,那么您可能会更好地选择@distributed for-loop。
请注意,如果您需要在转换后进行归约操作,@distributed for-loop 已经提供了一个,大部分归约将在本地应用,而最终归约将在调用进程上进行。但是,对于 pmap,您需要自己处理减少问题。
如果你真的需要,你也可以使用非常复杂的负载平衡和减少方案来实现自己的 pmap 函数。
https://docs.julialang.org/en/v1/manual/parallel-computing/