[英]Julia @parallel for loop with return statement
How can I write a parallel for loop in a function that returns for all workers as soon as a condition is met? 如何在满足条件的情况下为所有工作人员返回的函数中编写并行for循环?
Ie something like this: 就是这样的:
function test(n)
@sync @parallel for i in 1:1000
{... statement ...}
if {condition}
return test(n+1)
end
end
end
where all the workers stop working on the for loop and only the main process returns? 所有工人都停止在for循环上工作,只有主进程返回? (and the other processes start again working with the next for loop?)
(其他进程再次开始使用下一个for循环?)
The question seems like a basic pattern for doing "embarrassingly parallel" search tasks. 这个问题似乎是做“令人尴尬的并行”搜索任务的基本模式。 The
@parallel for
construct is good for partitioning work, but doesn't have the break
short-circuit logic for stopping as the for
in single process flow. @parallel for
构造适用于分区工作,但没有for
在单个进程流中作为for停止的break
短路逻辑。
To demonstrate how to do this in Julia consider a toy problem of finding the combination of a combination lock with several wheels. 为了演示如何在朱莉娅这样做,考虑一个玩具问题,找到一个组合锁与几个轮子的组合。 Each setting of a wheel can be checked for correctness with some method (taking a
combodelay
time - see code below). 可以使用某种方法检查车轮的每个设置的正确性(采用
combodelay
时间 - 请参阅下面的代码)。 After the correct number for a wheel is found, the next wheel is searched. 找到正确的车轮编号后,搜索下一个车轮。 The high level pseudo code is like the snippet given in the OP question.
高级伪代码就像OP问题中给出的片段一样。
The following is running code (on 0.5 and 0.6) to do this. 以下是运行代码(在0.5和0.6上)来执行此操作。 Some comments explain details, and the code is given in a single chunk for easy cut-and-paste.
一些注释解释了细节,代码在一个块中给出,以便于剪切和粘贴。
# combination lock problem parameters
const wheel_max = 1000 # size of wheel
@everywhere const magic_number = [55,10,993] # secret combination
const wheel_count = length(magic_number) # number of wheels
const combodelay = 0.01 # delay time to check single combination
# parallel short-circuit parameters
const check_to_work_ratio = 160 # ratio to limit short-circuit overhead
function find_combo(wheel,combo=Int[])
done = SharedArray{Int}(1) # shared variable to hold if and what combo
done[1] = 0 # succeded. 0 means not found yet
# setup counters to limit parallel overhead
@sync begin
@everywhere global localdone = false
@everywhere global checktime = 0.0
@everywhere global worktime = 0.0
end
# do the parallel work
@sync @parallel for i in 1:wheel_max
global localdone
global checktime
global worktime
# if not checking too much, look at shared variable
if !localdone && check_to_work_ratio*checktime < worktime
tic()
localdone = done[1]>0
checktime += toq()
end
# if no process found combo, check another combo
if !localdone
tic()
sleep(combodelay) # simulated work delay, {..statement..} from OP
if i==magic_number[wheel] # {condition} from OP
done[1] = i
localdone = true
end
worktime += toq()
else
break
end
end
if done[1]>0 # check if shared variable indicates combo for wheel found
push!(combo,done[1])
return wheel<wheel_count ? find_combo(wheel+1,combo) : (combo,true)
else
return (combo,false)
end
end
function find_combo_noparallel(wheel,combo=Int[])
found = false
i = 0
for i in 1:wheel_max
sleep(combodelay)
if i==magic_number[wheel]
found = true
break
end
end
if found
push!(combo,i)
return wheel<wheel_count ?
find_combo_noparallel(wheel+1,combo) : (combo,true)
else
return (combo,false)
end
end
function find_combo_nostop(wheel,combo=Int[])
done = SharedArray{Int}(1)
done[1] = 0
@sync @parallel for i in 1:wheel_max
sleep(combodelay)
if i==magic_number[wheel]
done[1] = i
end
end
if done[1]>0
push!(combo,done[1])
return wheel<wheel_count ?
find_combo_nostop(wheel+1,combo) : (combo,true)
else
return (combo,false)
end
end
result = find_combo(1)
println("parallel with short-circuit stopping: $result")
@assert result == (magic_number, true)
result = find_combo_noparallel(1)
println("single process with short-circuit stopping: $result")
@assert result == (magic_number, true)
result = find_combo_nostop(1)
println("parallel without short-circuit stopping: $result")
@assert result == (magic_number, true)
println("\ntimings")
print("parallel with short-circuit stopping ")
@time find_combo(1);
print("single process with short-circuit stopping ")
@time find_combo_noparallel(1)
print("parallel without short-circuit stopping ")
@time find_combo_nostop(1)
nothing
There could be better looking implementations, and some meta-programming can hide some of the short-circuit machinery. 可能有更好看的实现,一些元编程可以隐藏一些短路机制。 But this should be good as a start.
但这应该是一个好的开始。
Results should look approximately like this: 结果应该大致如下:
parallel with short-circuit stopping: ([55,10,993],true)
single process with short-circuit stopping: ([55,10,993],true)
parallel without short-circuit stopping: ([55,10,993],true)
timings
parallel with short-circuit stopping 4.473687 seconds
single process with short-circuit stopping 11.963329 seconds
parallel without short-circuit stopping 11.316780 seconds
This is calculated for demonstration with 3 worker processes. 这是为了演示3个工作进程而计算的。 Real problems should have many more processes and more work per process and then the benefits of short-circuiting will be evident.
真正的问题应该有更多的流程和每个流程更多的工作,然后短路的好处将是显而易见的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.