Parallel processing Julia-map函数状态

Parallel processing Julia-map函数状态,parallel-processing,julia,anonymous-function,pmap,Parallel Processing,Julia,Anonymous Function,Pmap,有没有一种舒适的方式可以在Julia中获得map/pmap的“状态” 如果我有一个数组a=[1:10],我想: 1:枚举数组并使用if-conditional添加打印命令 ((index,value) -> 5*value ......, enumerate(a) 在“…”所在的位置,有一种方法可以将匿名函数“链接”到 "5*value and then print index/length(a) if index%200 == 0" 2:知道是否已经有了这个选项,因为pmap用于并行

有没有一种舒适的方式可以在Julia中获得map/pmap的“状态”

如果我有一个数组a=[1:10],我想:

1:枚举数组并使用if-conditional添加打印命令

((index,value) -> 5*value ......, enumerate(a)
在“…”所在的位置,有一种方法可以将匿名函数“链接”到

"5*value and then print index/length(a) if index%200 == 0"
2:知道是否已经有了这个选项,因为pmap用于并行任务,这些任务通常用于大型流程,所以它应该已经存在了

另外,有没有一种方法可以让匿名函数一个接一个地执行两个“独立”的操作

示例

如果我有

a = [1:1000]
function f(n) #something that takes a huge ammount of time
end 
我执行

map(x -> f(x), a)
REPL将打印出状态

"0.1 completed"
.
.
.
"0.9 completed"
解决方案

ProgressMeter包在默认情况下不包含此项,这一点很奇怪

Pkg.add("ProgressMeter")
Pkg.clone("https://github.com/slundberg/PmapProgressMeter.jl")
@everywhere using ProgressMeter
@everywhere using PmapProgressmeter
pmap(x->begin sleep(1); x end, Progress(10), 1:10)

在github上

为什么不在函数定义中包含它来打印这些信息?例如

function f(n) #something that takes a huge amount of time
    ...
    do stuff.
    ...
    println("completed $n")
end 
并且,如果需要,您可以向函数中添加一个额外的参数,该参数将包含
0.1
<在您的示例中,code>0.9(我不太确定它们是什么,但不管它们是什么,它们可以只是函数中的一个参数)

如果您查看下面关于
pmap
@parallel
的示例,您将发现一个函数示例,该函数被馈送到
pmap
,用于打印输出

有关将多个参数提供给与
map
pmap
一起使用的函数的信息,请参见等帖子



朱莉娅建议

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 for idx = 1:12
    parallel_func(idx)
end
pmap(parallel_func, 1:12)
现在,对于
@parallel
测试,我们运行以下程序:

addprocs(2)

@everywhere begin
    function parallel_func(idx)
        workernum = myid() - 1 
        sleep(workernum)
        println("job $idx")
    end
end
@parallel for idx = 1:12
    parallel_func(idx)
end
pmap(parallel_func, 1:12)
并返回打印输出:

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
测试,我运行以下命令:

addprocs(2)

@everywhere begin
    function parallel_func(idx)
        workernum = myid() - 1 
        sleep(workernum)
        println("job $idx")
    end
end
@parallel for idx = 1:12
    parallel_func(idx)
end
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

现在,请注意,worker2已经执行了8个作业,worker 3执行了4个工作。这与它们的速度和我们想要的最佳效率成正比
pmap
是一个很难的任务主控程序-根据每个人的能力进行分配。

您可以通过实现“关闭”来创建一个带有“状态”的函数。例如

julia> F = function ()
  ClosedVar = 5
  return (x) -> x + ClosedVar
end;
julia> f = F();
julia> f(5)
10
julia> ClosedVar = 1000;
julia> f(5)
10
如您所见,函数
f
保持“状态”(即内部变量
ClosedVar
f
的本地变量,
f
保持对它的访问,即使
f
本身在技术上早已超出范围

请注意与正常、非闭合函数定义的区别:

julia> MyVar = 5;
julia> g(x) = 5 + MyVar;
julia> g(5)
10
julia> MyVar = 1000;
julia> g(5)
1005
您可以创建自己的闭包,该闭包在运行时查询/更新其关闭的变量,并根据每次的状态执行不同的操作

话虽如此,从您的示例中,您似乎期望
pmap
将按顺序运行。这是不能保证的。因此,不要依赖“此线程处理的是哪个索引”方法来打印每200个操作。您可能必须在闭包中维护一个关闭的“计数器”变量,并依赖于此。这可能是因此,这意味着您的闭包需要在任何地方都可访问

具有pmap分支


你也可以让Juno进度条在pmap内部工作。这有点像使用未记录的东西,因此你应该在中询问是否需要更多信息,因为发布此公共信息只会在它发生变化时混淆人们。

另一种可能是使用
共享Darray
作为工作人员之间共享的计数器。Eg

addprocs(2)

Counter = convert(SharedArray, zeros(Int64, nworkers()))

## Make sure each worker has the SharedArray declared on it, so that it need not be fed as an explicit argument
function sendto(p::Int; args...)
  for (nm, val) in args
    @spawnat(p, eval(Main, Expr(:(=), nm, val)))
  end
end

for (idx, pid) in enumerate(workers())
  sendto(pid, Counter = Counter)
end
@everywhere global Counter


@everywhere begin
    function do_stuff(n)
        sleep(rand())
        Counter[(myid()-1)] += 1
        TotalJobs = sum(Counter)
        println("Jobs Completed = $TotalJobs")
    end
end

pmap(do_stuff, 1:10)

不清楚状态是什么意思。请给出一个特定输入向量所需输出的示例。“状态”在评估过程中,我发布了一个示例来说明你是对的,这是一个很好的解决方法。我以前(错误地)读到pmap只能接受一个函数和一个“单个”向量作为一个参数,结果是不正确的,所以通过提供一个额外的“计数”向量以从该函数打印出来,或多或少地解决了这个问题。但是,作为pmap的参数,这并不是很好…可能最好传递一个闭包,在调用时自动更新其状态。我想你可以这样做一个双参数函数,还传递一个“索引”数组到map以跟踪处理的项目…但是,这对于pmap来说是不可靠的,因为它是n