2017-04-15 14 views
7

条件が満たされるとすぐにすべてのワーカーを返す関数に並列forループを書くにはどうすればよいですか?Julia @parallel for return文

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として停止するための短絡ロジックは、単一プロセスフローではありません(break)。

ジュリアでこれを行う方法を実証するには、いくつかのホイールと組み合わせたロックの組み合わせを見つけるというおもちゃの問題を考えてみましょう。ホイールの各設定は、いくつかの方法(正確には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つのワーカー・プロセスとのデモンストレーションのために計算されます。実際の問題には、より多くのプロセスとプロセスごとの作業が必要であり、短絡のメリットが明らかになります。

関連する問題