【问题标题】:Difference between parallel map and parallel for-loop并行map和并行for循环的区别
【发布时间】:2019-09-05 22:48:43
【问题描述】:

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

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

pmap@distributed for 之间有什么区别?为什么@distributed for 处理大量工作时速度很慢?

谢谢

【问题讨论】:

    标签: parallel-processing julia distributed pmap


    【解决方案1】:

    问题是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
    

    您可以看到,大型作业(值 10)使 pmap 对不同于获得大型作业的工人执行所有小型作业(在我的示例中,工人 5 只完成了作业 10而工人24 做了所有其他工作)。另一方面,@distributed for 为每个工人分配了相同数量的工作。因此,获得工作10 的工人(第二个示例中的工人2)仍然必须做四份短期工作(因为平均每个工人必须做5 工作 - 我的示例总共有20 工作和4工人)。

    现在@distributed for 的优势在于,如果工作成本低,那么在工作人员之间平等分配工作就可以避免进行动态调度,而这也不是免费的。

    总而言之,正如文档所述,如果作业成本高昂(尤其是在其运行时间变化很大的情况下),最好使用pmap,因为它会进行负载平衡。

    【讨论】:

      【解决方案2】:

      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/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-05
        • 2017-04-18
        • 2016-08-10
        • 2013-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多