2012-03-30 13 views
6

साइड इफेक्ट्स के साथ संचालन करने के उद्देश्य से समांतर संग्रह हैं? यदि हां, तो आप दौड़ की स्थिति से कैसे बच सकते हैं? उदाहरण के लिए:स्कैला समांतर संग्रह के साथ दौड़ की स्थिति से कैसे बचें

var sum=0 
(1 to 10000).foreach(n=>sum+=n); println(sum) 

50005000 

इसके साथ कोई समस्या नहीं है। लेकिन अगर parallelize करने की कोशिश, दौड़ की स्थिति होती हैं:

var sum=0 
(1 to 10000).par.foreach(n=>sum+=n);println(sum) 

49980037 
+0

नहीं, दुष्प्रभाव खराब हैं। यदि आपके पास राज्य नहीं है, तो दौड़ की स्थिति रखना मुश्किल है। – PlexQ

उत्तर

17

त्वरित जवाब: ऐसा नहीं है। समांतर कोड समांतर होना चाहिए, समवर्ती नहीं।

बेहतर जवाब:

val sum = (1 to 10000).par.reduce(_+_) // depends on commutativity and associativity 

भी aggregate देखें।

4

समानांतर मामले काम नहीं करता है क्योंकि आप अस्थिर चर इसलिए अपने लेखन की दृश्यता सुनिश्चित नहीं और उपयोग नहीं करते हैं, क्योंकि आप एक से अधिक थ्रेड कि निम्न है:

  1. एक रजिस्टर में sum पढ़
  2. sum मूल्य
  3. साथ रजिस्टर करने के लिए जोड़ अद्यतन मूल्य वापस स्मृति करने के लिए

अगर 2 धागे बारे में चरण 1 पहले ओ करना दूसरे के बाद ne और फिर किसी भी क्रम में उपर्युक्त चरणों को करने के लिए आगे बढ़ें, वे अद्यतनों में से एक को ओवरराइट करना समाप्त कर देंगे।

  1. इस तरह कुछ करने पर sum की दृश्यता सुनिश्चित करने के लिए @volatile एनोटेशन का उपयोग करें। here देखें।
  2. @volatile के साथ भी, वृद्धि की गैर-परमाणुता के कारण आप कुछ वृद्धि खो देंगे। आपको AtomicInteger एस और उनके incrementAndGet का उपयोग करना चाहिए।
  3. हालांकि परमाणु काउंटर का उपयोग करने से शुद्धता सुनिश्चित होगी, यहां साझा चर होने से प्रदर्शन में काफी बाधा आती है - आपका साझा चर अब एक प्रदर्शन बाधा है क्योंकि प्रत्येक थ्रेड परमाणु रूप से उसी कैश लाइन पर लिखने की कोशिश करेगा। यदि आपने इस चर को अक्सर लिखा है, तो यह कोई समस्या नहीं होगी, लेकिन चूंकि आप इसे प्रत्येक पुनरावृत्ति में करते हैं, इसलिए यहां कोई गति नहीं होगी - असल में, प्रोसेसर के बीच कैश-लाइन स्वामित्व हस्तांतरण के कारण, यह शायद धीमा हो जाएगा ।

तो, जैसा कि डैनियल ने सुझाव दिया - इसके लिए reduce का उपयोग करें।

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