2017-04-15 52 views
7

如何在函数中编写并行for循环,只要满足条件就返回所有工作人员?Julia @parallel for return with return statement

I.e.这样的事情:

function test(n) 
    @sync @parallel for i in 1:1000 
    {... statement ...} 
    if {condition} 
     return test(n+1) 
    end 
    end 
end 

其中所有的工人停止for循环工作,只有主进程返回? (并且其他进程再次开始与下一个for循环一起工作?)

回答

3

这个问题似乎是做“尴尬平行”搜索任务的基本模式。 @parallel for结构适用于分区工作,但没有用于停止的短路逻辑,因为for在单个处理流程中。

为了演示如何在Julia中做到这一点,考虑寻找具有多个轮子的组合锁的玩具问题。可以使用某种方法检查车轮的每个设置是否正确(采取combodelay时间 - 请参阅下面的代码)。在找到正确的车轮编号后,搜索下一个车轮。高级别伪代码就像OP问题中给出的代码片段一样。

以下是正在运行的代码(在0.5和0.6上)来执行此操作。一些评论解释了细节,并且代码在一个块中给出,以便于剪切和粘贴。

# 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 

可能有更好看的实现,一些元编程可以隐藏一些短路机械。但这应该是一个很好的开始。

结果应该大致是这样的:

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 

这是计算与3个工作进程的示范。真正的问题应该有更多的过程和每个过程的更多工作,然后短路的好处将是显而易见的。