何时使用 parallel 与 pmap

Julia 文档建议这样做

pmap() 是针对每个函数调用执行大量工作的情况而设计的。相比之下,@ parallel for 可以处理每次迭代很小的情况,也许只是将两个数相加。

有几个原因。首先,pmap 会带来更大的启动成本,从而为员工创造就业机会。因此,如果作业非常小,这些启动成本可能变得低效。然而,相反,pmap 在工人中分配工作的聪明工作。特别是,它构建了一个作业队列,并在该工作人员可用时向每个工作人员发送新作业。相比之下,@parallel 将所有工作分配给工人。因此,如果一些工人的工作时间比其他工人长,那么你最终可能会遇到这样的情况,即大多数工人已经完成并且闲置,而少数工人在过长的时间内仍然活跃,完成工作。然而,这种情况不太可能发生在非常小而简单的工作中。

以下说明了这一点:假设我们有两个工人,其中一个工作缓慢,另一个工作速度快两倍。理想情况下,我们希望快速工作者的工作量是慢工作者的两倍。 (或者,我们可以有快速和慢速的工作,但校长完全相同)。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 是一个艰巨的任务大师 - 从每个人的能力。