2017-04-15 11 views
7

मैं एक ऐसे कार्य में लूप के लिए समानांतर कैसे लिख सकता हूं जो सभी श्रमिकों के लिए एक शर्त पूरी होने पर लौटता है?वापसी के साथ लूप के लिए जूलिया @parallel

आईई। इस तरह कुछ:

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

जहां सभी कर्मचारी लूप के लिए काम करना बंद कर देते हैं और केवल मुख्य प्रक्रिया लौटते हैं? (और अन्य प्रक्रियाएं लूप के लिए अगले के साथ फिर से काम करना शुरू कर देती हैं?)

उत्तर

3

प्रश्न "शर्मनाक समानांतर" खोज कार्यों को करने के लिए मूलभूत पैटर्न की तरह लगता है। @parallel for निर्माण विभाजन के काम के लिए अच्छा है, लेकिन break शॉर्ट-सर्किट तर्क नहीं है जो for को एकल प्रक्रिया प्रवाह में रोकने के लिए है।

यह दिखाने के लिए कि जूलिया में ऐसा करने के लिए कई पहियों के साथ संयोजन लॉक के संयोजन को खोजने की खिलौना समस्या पर विचार करें। किसी विधि के साथ एक व्हील की प्रत्येक सेटिंग को सहीता के लिए चेक किया जा सकता है (combodelay समय लेना - नीचे कोड देखें)। एक पहिया के लिए सही संख्या मिलने के बाद, अगला पहिया खोजा जाता है। उच्च स्तरीय छद्म कोड ओपी प्रश्न में दिए गए स्निपेट की तरह है।

ऐसा करने के लिए निम्नलिखित कोड (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 कार्यकर्ता प्रक्रियाओं के साथ प्रदर्शन के लिए की जाती है। वास्तविक समस्याओं में प्रति प्रक्रिया कई और प्रक्रियाएं होनी चाहिए और फिर शॉर्ट सर्किटिंग के लाभ स्पष्ट होंगे।

संबंधित मुद्दे