正如标题所述:@parallel
和pmap
之间究竟有什么区别?我并不是说明显的一个是循环的宏而另一个是关于函数的,我的意思是它们的实现究竟是如何不同的,我应该如何使用这些知识在它们之间进行选择?
我问的原因是我编写的很多应用程序都可以使用这两种构造:我可以编写一个循环并用@parallel
计算一些东西,或者将循环中的内容包装成函数并调用pmap
就此而言。我一直在遵循使用@parallel
进行快速评估的建议和pmap
对于每个任务需要更长时间的调用(如文档中所述)的建议,但我觉得如果我有更好地了解它正在做什么我能够做出更好的选择。
例如:@parallel
在评估之前是否将工作分开?我注意到如果我运行一个并行循环,其中每个内部调用需要一段随机时间,@parallel
可能需要很长时间,因为最后我只有很少的进程仍在工作。 pmap
在相同的微型测试中似乎没有这个:pmap
是否根据需要重新分配工作?
这样的其他问题都源于我对pmap
与@parallel
的确切区别的无知。
答案 0 :(得分:18)
@parallel
将完成工作,并在可用的工作人员立即之间进行分工。相反,?@parallel
中的注意事项我们会得到The specified range is partitioned ... across all workers.
pmap
,这将启动每个工作人员的工作。一旦工人完成工作,它将为其提供下一个可用工作。它类似于基于队列的多处理,例如在python中很常见。因此,它不是一个“重新分配”工作的情况,而是仅仅在适当的时候将它发布出去,而不是首先给予正确的工作人员。
我制作了以下示例,我相信这说明了这一点。在这个有点愚蠢的例子中,我们有两个工人,其中一个是慢的,另一个是两倍的工作。理想情况下,我们希望快速工作者的工作量是慢工作者的两倍。 (或者,更现实地说,我们会有快速和慢速的工作,但校长是完全相同的)。 pmap
将完成此操作,但@parallel
不会。
对于每个测试,我初始化以下内容:
addprocs(2)
@everywhere begin
function parallel_func(idx)
workernum = myid() - 1
sleep(workernum)
println("job $idx")
end
end
现在,对于@parallel
测试,我运行以下命令:
@parallel for idx = 1:12
parallel_func(idx)
end
获取打印输出:
julia> From worker 2: job 1
From worker 3: job 7
From worker 2: job 2
From worker 2: job 3
From worker 3: job 8
From worker 2: job 4
From worker 2: job 5
From worker 3: job 9
From worker 2: job 6
From worker 3: job 10
From worker 3: job 11
From worker 3: job 12
这几乎是甜蜜的。工人们平均“分享”了工作。请注意,每个工作人员已完成6个工作,即使工人2的工作速度是工人3的两倍。可能会触及,但效率低下。
对于pmap
测试,我运行以下内容:
pmap(parallel_func, 1:12)
并获得输出:
From worker 2: job 1
From worker 3: job 2
From worker 2: job 3
From worker 2: job 5
From worker 3: job 4
From worker 2: job 6
From worker 2: job 8
From worker 3: job 7
From worker 2: job 9
From worker 2: job 11
From worker 3: job 10
From worker 2: job 12
现在,请注意,工人2已执行了8个工作,而工人3执行了4个工作。这与他们的速度和我们想要的最佳效率成正比。 pmap
是一个艰巨的任务主人 - 每个人根据他们的能力。
因此,Julia文档中的建议是有道理的。如果您有简单的小工作,那么@parallel
的这些问题更有可能不会导致问题。但是,对于更大或更复杂的工作,pmap
具有优势。