2013-02-11 7 views
8

का उपयोग करके समानांतर में संख्याओं की एक बड़ी सूची के योग की गणना कैसे कर सकता हूं। मैं यह समझने की कोशिश कर रहा हूं कि समानांतर में बड़े अनुक्रम में एक सरल ऑपरेशन को कुशलतापूर्वक लागू करने के लिए क्लोजर का उपयोग कैसे करें। मैं कुछ गति प्राप्त करने के लिए अपनी मशीन पर एकाधिक कोर का लाभ उठाने के लिए समांतर समाधान का उपयोग करने में सक्षम होना चाहता हूं।क्लोजर

मैं विभाजन के साथ संयोजन में pmap का उपयोग करने का प्रयास कर रहा हूं-सभी इनपुट seq में प्रत्येक आइटम के लिए भविष्य बनाने के ऊपरी हिस्से को कम करने के लिए। दुर्भाग्य से, विभाजन-सभी प्रत्येक विभाजन seq के पूर्ण मूल्यांकन को मजबूर करता है। यह मेरी मशीन पर OutOfMemoryError का कारण बनता है।

(defn sum [vs] 
    (reduce + vs)) 

(def workers 
    (+ 2 (.. Runtime getRuntime availableProcessors))) 

(let 
    [n 80000000 
    vs (range n)] 

    (time (sum vs)) 
    (time (sum (pmap sum (partition-all (long (/ n workers)) vs))))) 

मैं बड़े इनपुट सेट में योग कैसे लागू कर सकता हूं, और धारावाहिक कार्यान्वयन के प्रदर्शन को हरा सकता हूं?

समाधान reducers पुस्तकालय ओर इशारा करते हुए के लिए @Arthur Ulfeldt को

धन्यवाद। Reducers का उपयोग कर समाधान यहाँ है। बहु-कोर मशीन पर चलते समय यह कोड अपेक्षित प्रदर्शन सुधार दिखाता है। (नोट: मैं बनाम बदल दिया है समय और अधिक सटीक हो बनाने के लिए एक समारोह होने के लिए)

(require '[clojure.core.reducers :as r]) 

(let 
    [n 80000000 
    vs #(range n)] 

    (time (reduce + (vs))) 
    (time (r/fold + (vs))) 
+0

मात्रा गलत तरीके से कर रहे हैं चारों ओर? '(विभाजन- सभी मजदूर बनाम)' '(/ एन श्रमिक) 'लंबाई' श्रमिकों के अनुक्रम 'बनाता है। क्या आप नहीं चाहते '(विभाजन-सभी (लंबे (/ एन श्रमिक) बनाम)'? –

+0

@ ए। वेब, आपके सुधार के लिए धन्यवाद। मैं सवाल में संशोधन करूंगा। यह फिक्स समानांतर संस्करण को थोड़ा तेज़ बनाने में मदद करता है, लेकिन यह अभी भी धारावाहिक कार्यान्वयन को हरा नहीं सकता है, और यह अभी भी बहुत बड़े इनपुट पर स्मृति से बाहर चला जाता है। –

उत्तर

8

pmap मैं ने पाया है कि काफी बड़ी मात्रा स्विचिंग पर काबू पाने के लिए आवश्यक हैं और भविष्य भूमि के ऊपर का उपयोग करते समय एक हिस्सा कोशिश + जितनी तेजी से एक opperation के लिए 10,000 का आकार। संभावित लाभ भाग उत्पन्न करने के ऊपरी हिस्से से बंधे होते हैं। इसके परिणामस्वरूप इष्टतम मूल्य होता है जो उपलब्ध कोरों और हिस्सों को बनाने के लिए आवश्यक समय को संतुलित करता है। इस मामले में + वर्कलोड के रूप में मैं इसे एकल थ्रेडेड विकल्प से तेज़ बनाने में असमर्थ था।

आप pmap बिना ऐसा करने में और संभावित कांटा का उपयोग कर रुचि रखते हैं/में शामिल होने की जाँच नई (ish) reducers library

OOM स्थिति पहले टेस्ट (range n) से आलसी अनुक्रम को साकार जो तब बनाए रखा है से आता है इसलिए इसे दूसरे अनुक्रम में पारित किया जा सकता है।

अगर मैं + समारोह बहुत एक slow+ समारोह को परिभाषित करते हुए की गति धीमी हो और उस एकल थ्रेड, मात्रा से अधिक pmap, और reducers बीच diference डब्ल्यू/दिखाई बन forkJoin का उपयोग करें:

user> *clojure-version*                
{:major 1, :minor 5, :incremental 0, :qualifier "RC15"} 
(require '[clojure.core.reducers :as r]) 

(def workers 
    (+ 2 (.. Runtime getRuntime availableProcessors))) 

(defn slow+ 
    ([] 0) 
    ([x] x) 
    ([x y] (reduce + (range 100000)) (+ x y))) 

(defn run-test [] 
    (let [n 8000] 
    (time (reduce slow+ (range n))) 
    (time (reduce slow+ (pmap #(reduce slow+ %) (partition-all (* workers 100) (range n))))) 
    (time (r/fold slow+ (vec (range n)))))) 

user> (run-test) 
"Elapsed time: 28655.951241 msecs" ; one thread 
"Elapsed time: 6975.488591 msecs" ; pmap over chunks 
"Elapsed time: 8170.254426 msecs" ; using reducer