2017-04-15 75 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個工作進程的示範。真正的問題應該有更多的過程和每個過程的更多工作,然後短路的好處將是顯而易見的。