并行映射和并行for循环之间的区别

Tia*_*hao 5 parallel-processing distributed pmap julia

当我阅读Julia的多核并行计算文档时,我注意到同时存在并行映射pmap和for-loop @distributed for

从文档中可以看出,“ Julia pmap是为每个函数调用都需要大量工作的情况而设计的。相比之下,Julia @distributed for可以处理每次迭代很小的情况”。

pmap和 之间有什么区别@distributed for?为什么@distributed for要花大量时间进行缓慢工作?

谢谢

Bog*_*ski 5

问题是pmap@distributed for将作业分成相等的块的同时进行负载平衡。您可以通过运行以下两个代码示例来确认这一点:

julia> @time res = pmap(x -> (sleep(x/10); println(x)), [10;ones(Int, 19)]);
      From worker 2:    1
      From worker 3:    1
      From worker 4:    1
      From worker 2:    1
      From worker 3:    1
      From worker 4:    1
      From worker 3:    1
      From worker 2:    1
      From worker 4:    1
      From worker 4:    1
      From worker 2:    1
      From worker 3:    1
      From worker 2:    1
      From worker 3:    1
      From worker 4:    1
      From worker 4:    1
      From worker 3:    1
      From worker 2:    1
      From worker 4:    1
      From worker 5:    10
  1.106504 seconds (173.34 k allocations: 8.711 MiB, 0.66% gc time)

julia> @time @sync @distributed for x in [10;ones(Int, 19)]
       sleep(x/10); println(x)
       end
      From worker 4:    1
      From worker 3:    1
      From worker 5:    1
      From worker 4:    1
      From worker 5:    1
      From worker 3:    1
      From worker 5:    1
      From worker 3:    1
      From worker 4:    1
      From worker 3:    1
      From worker 4:    1
      From worker 5:    1
      From worker 4:    1
      From worker 5:    1
      From worker 3:    1
      From worker 2:    10
      From worker 2:    1
      From worker 2:    1
      From worker 2:    1
      From worker 2:    1
  1.543574 seconds (184.19 k allocations: 9.013 MiB)
Task (done) @0x0000000005c5c8b0
Run Code Online (Sandbox Code Playgroud)

你可以看到,大型作业(值10),使pmap执行对工人比一个拿到了大型作业的所有不同小的工作(在我的例子工人5做的唯一工作10,而工作人员24所做的一切其他工作)。另一方面@distributed for,为每个工人分配了相同数量的工作。因此,找到工作的工人102第二个示例中的工人)仍然不得不做四项短期工作(因为平均每个工人都必须从事5工作-我的示例中共有20职位和4工人)。

现在的好处@distributed for是,如果工作便宜,那么在工人之间平均分配工作就不必进行也不是免费的动态调度。

总而言之,如文档所述,如果作业很昂贵(尤其是其运行时间可能相差很大),则最好使用pmap它,因为它可以实现负载平衡。


hck*_*ckr 5

pmap有一个batch_size参数,默认情况下为 1。这意味着集合的每个元素将一个一个地发送给可用的工作人员或任务,以便由您提供的函数进行转换。如果每个函数调用都做了大量的工作,也许每个调用花费的时间不同,使用pmap的好处是不让worker空闲,而其他worker在做工作,因为当一个worker完成一次转换时,它会要求要转换的下一个元素。因此,pmap有效地平衡了工人/任务之间的负载

@distributed但是,for 循环在开始时在工作人员之间划分给定范围一次,不知道该范围的每个分区将花费多长时间。例如,考虑一个矩阵集合,其中集合的前一百个元素是 2×2 矩阵,接下来的一百个元素是 1000×1000 矩阵,我们想使用@distributedfor取每个矩阵的逆-loops 和 2 个工作进程。

@sync @distributed for i = 1:200
    B[i] = inv(A[i])
end
Run Code Online (Sandbox Code Playgroud)

第一个工作人员将获得所有 2×2 矩阵,第二个工作人员将获得 1000×1000 矩阵。第一个worker会很快完成所有的转换并闲置,而另一个会继续工作很长时间。尽管您使用了 2 个 worker,但整个工作的主要部分将在第二个 worker 上有效地串行执行并且使用多个 worker 几乎没有任何好处。这个问题在并行计算的上下文中被称为负载平衡。该问题也可能出现,例如,即使要完成的工作是同质的,当一个处理器慢而另一个处理器快时。

然而,对于非常小的工作转换,使用pmap小批量会产生可能很重要的通信开销,因为在每个批处理之后,处理器需要从调用进程中获取下一个批处理,而对于@distributedfor 循环,每个工作进程都会知道,一开始,它负责范围的哪一部分。

pmap@distributedfor 循环之间的选择取决于您想要实现的目标。如果您要转换一个集合,map并且每个转换都需要大量的工作并且这个工作量是变化的,那么您可能会更好地选择pmap. 如果每个转换都非常小,那么您可能会更好地选择@distributedfor 循环。

需要注意的是,如果转换后需要进行归约操作,@distributedfor循环已经提供了,大部分归约会在本地应用,而最终的归约将在调用过程中进行。pmap但是,对于,您需要自己处理减少。

pmap如果您确实需要,您还可以使用非常复杂的负载平衡和减少方案来实现您自己的功能。

https://docs.julialang.org/en/v1/manual/parallel-computing/