当我阅读Julia的多核并行计算文档时,我注意到并行映射pmap
和for循环@distributed for
都存在。
从文档中,“ Julia的pmap
是为每个函数调用都需要大量工作的情况而设计的。相反,@distributed for
可以处理每次迭代很小的情况。” >
pmap
和@distributed for
之间有什么区别?为什么@distributed for
处理大量工作很慢?
谢谢
答案 0 :(得分: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
您会看到,大型作业(值10
)使pmap
在不同于获得大型作业的工人(在我的示例中为工人5
)上执行所有小型作业仅10
工作,而2
至4
的工作人员完成了所有其他工作)。另一方面,@distributed for
为每个工人分配了相同数量的工作。因此,获得工作10
的工人(在第二个示例中为工人2
)仍然不得不做四项短期工作(因为平均每个工人必须完成5
个工作-我的示例中有总共20
个工作和4
个工作人员。)
现在@distributed for
的优势在于,如果工作便宜,那么在工人之间平均分配工作就不必进行动态调度,而该动态调度也不是免费的。
总而言之,如文档所述,如果这项工作很昂贵(尤其是其运行时间可能相差很大),则最好使用pmap
来完成负载均衡。
答案 1 :(得分:3)
pmap
具有一个batch_size
参数,默认情况下为1。这意味着该集合中的每个元素都将一个一个地发送给可用的工作程序或任务由您提供的功能进行转换。如果每个函数调用都执行大量工作,并且每个调用所花费的时间可能有所不同,则使用pmap
的好处是不会让工作人员闲置,而其他工作人员却可以工作,因为当一个工作人员完成一个转换时,它将要求下一个要转换的元素。因此,pmap
有效地平衡工作人员/任务之间的负载。
@distributed
for循环在开始时就在工作人员中一次 划分给定范围,而不知道该范围的每个分区将花费多少时间。例如,考虑一个矩阵集合,其中集合的前100个元素是2×2矩阵,接下来的100个元素是1000×1000矩阵,我们希望使用{ {1}} for循环和2个工作进程。
@distributed
第一个工作人员将获得所有2×2矩阵,第二个工作人员将获得1000×1000矩阵。第一个工作人员将很快完成所有转换并变得闲置,而另一个工作人员将继续工作很长时间。尽管您使用的是2个工作程序,但是整个工作的大部分将有效地在第二个工作程序上依次执行 ,并且使用多个工作程序几乎不会带来任何好处。在并行计算的上下文中,此问题称为负载平衡。例如,即使要完成的工作是同质的,一个处理器速度较慢而另一个处理器速度较快时,也会出现此问题。
对于非常小的工作转换,使用@sync @distributed for i = 1:200
B[i] = inv(A[i])
end
并具有较小的批处理量会产生很大的通信开销,因为每批处理后处理器都需要从调用过程中获取下一个批处理,而{ {1}} for-loops每个工作进程从一开始就知道它负责范围的哪一部分。
在pmap
和@distributed
for循环之间进行选择取决于您要实现的目标。如果要像在pmap
中那样转换集合,并且每次转换都需要大量的工作并且数量是变化的,那么选择@distributed
可能会更好。如果每个转换都非常小,那么最好选择map
for循环。
请注意,如果在转换后需要进行约简操作,则pmap
for循环已经提供了一个约简,大部分约简将在本地应用,而最后的约简将在调用过程中进行。但是,使用@distributed
,您将需要自己处理减少量。
如果确实需要,还可以使用非常复杂的负载平衡和减少方案来实现自己的@distributed
函数。