2012-02-06 29 views
7

क्या कोई समझा सकता है, यह प्रोग्राम sqrt_min के लिए सही मान क्यों लौटा रहा है?समानांतर .foreach काम करता है, लेकिन क्यों?

int n = 1000000; 

double[] myArr = new double[n]; 
for(int i = n-1 ; i>= 0; i--){ myArr[i] = (double)i;} 

// sqrt_min contains minimal sqrt-value 
double sqrt_min = double.MaxValue; 

Parallel.ForEach(myArr, num => 
{ 
double sqrt = Math.Sqrt(num); // some time consuming calculation that should be parallized 
if(sqrt < sqrt_min){ sqrt_min = sqrt;} 
}); 
Console.WriteLine("minimum: "+sqrt_min); 
+1

भी http://stackoverflow.com/questions/3679209/why-doesnt-this-code-demonstrate-the-non-atomicity-of-reads-writes यह भाग्य नहीं हो सकता है देखते हैं। ऐसा इसलिए हो सकता है क्योंकि आपका सीपीयू परमाणु डबल ऑपरेशंस प्रदान करता है भले ही सी # इसकी गारंटी नहीं देता है। – hatchet

+1

ऐसी संभावना है कि इस बग को ठीक करने से पर्याप्त ताला विवाद हो जाएगा कि यह केवल एक धागे पर वर्ग की जड़ों की गणना करने से धीमा होगा। एक बेहतर समाधान यह होगा कि प्रत्येक सीपीयू कई वर्ग जड़ों की गणना करे, अपने स्वयं के न्यूनतम सीमाओं का ट्रैक रखे, और प्रत्येक सीपीयू के दौरान वैश्विक न्यूनतम खोज लें। आपके पास अभी भी विवाद होगा, लेकिन विवाद केवल प्रत्येक एकल वर्ग रूट के बजाय थ्रेड-विशिष्ट स्थानीय न्यूनतम की तुलना करते समय लागू होगा। – Brian

उत्तर

13

यह बहुत भाग्य से काम करता है। कभी-कभी जब आप इसे चलाते हैं तो आप भाग्यशाली हैं कि गैर-परमाणु डबल को पढ़ता है और लिखता है जिसके परिणामस्वरूप "टूटा" मान नहीं होते हैं। कभी-कभी आप भाग्यशाली हैं कि गैर-परमाणु परीक्षण और सेट बस उस दौड़ के दौरान सही मान निर्धारित करने के लिए होते हैं। इस बात की कोई गारंटी नहीं है कि यह कार्यक्रम किसी विशेष परिणाम का उत्पादन करता है।

+0

तो इस मुद्दे को हल करने का सबसे अच्छा तरीका क्या है? – user1193134

+1

@ user1193134: सामान्य रूप से, ताले या (बेहद सावधान) परमाणु संचालन। आपके विशेष मामले में, PLINQ 'कुल()' या बस 'न्यूनतम()'। – SLaks

+0

क्या आप मुझे इस समस्या को हल करने में हाथ दे सकते हैं? – user1193134

5

आपका कोड सुरक्षित नहीं है; यह केवल संयोग से काम करता है।

दो धागे एक साथ if चलाते हैं, तो न्यूनतम से एक ओवरराइट किया जाएगा:

  • sqrt_min = 6
  • थ्रेड एक: sqrt = 5
  • थ्रेड बी: sqrt = 4
  • थ्रेड एक if
  • में प्रवेश करती है
  • थ्रेड बी if
  • में प्रवेश करता है
  • थ्रेड बी sqrt_min = 4
  • थ्रेड एक प्रदान करती है sqrt_min = 5

32-बिट सिस्टम पर प्रदान करती है, तो आप भी पढ़ने के लिए/लिखने फाड़ कमजोर कर रहे हैं।

लूप में Interlocked.CompareExchange का उपयोग करके इसे सुरक्षित बनाना संभव होगा।

+0

जो मैंने सोचा था! लेकिन मैं इस बिंदु पर कभी नहीं मिला! यहां तक ​​कि बहुत कठिन और काफी बार कोशिश करके> 10^9 – user1193134

+0

@ user1193134: सरणी का आकार वास्तव में कोई फर्क नहीं पड़ता (जब तक आपके पास सैकड़ों कोर नहीं होते)। Dasblinkenlight के संशोधन का उपयोग, मुझे लगातार विफलता मिलती है। – SLaks

+0

आप Interlocked.CompareExchange चीज़ से बहुत परिचित प्रतीत होते हैं। क्या आप मुझे समस्या के साथ हाथ दे सकते हैं? – user1193134

3

आपका कोड वास्तव में काम नहीं करता है: मैं एक पाश में 100,000 बार यह भाग गया, और यह मेरी 8 कोर कंप्यूटर पर एक बार में विफल रहा है, यह उत्पादन उत्पादन:

minimum: 1 

मैं त्रुटि बनाने के लिए रन छोटा तेजी से दिखाई देते हैं।

यहाँ मेरी संशोधनों हैं:

static void Run() { 
    int n = 10; 

    double[] myArr = new double[n]; 
    for (int i = n - 1; i >= 0; i--) { myArr[i] = (double)i*i; } 

    // sqrt_min contains minimal sqrt-value 
    double sqrt_min = double.MaxValue; 

    Parallel.ForEach(myArr, num => { 
     double sqrt = Math.Sqrt(num); // some time consuming calculation that should be parallized 
     if (sqrt < sqrt_min) { sqrt_min = sqrt; } 
    }); 
    if (sqrt_min > 0) { 
     Console.WriteLine("minimum: " + sqrt_min); 
    } 
} 


static void Main() { 
    for (int i = 0; i != 100000; i++) { 
     Run(); 
    } 
} 

यह एक संयोग है, पढ़ने और एक साझा चर के लेखन के आसपास तुल्यकालन की कमी पर विचार नहीं है।

+0

मुझे भी विफलता मिली। – SLaks

2

जैसा कि अन्य ने कहा है, यह केवल कतरनी किस्मत के आधार पर काम करता है। ओपी और अन्य पोस्टर्स दोनों को वास्तव में दौड़ की स्थिति बनाने में परेशानी हुई है। यह काफी आसानी से समझाया गया है। कोड बहुत सारी दौड़ की स्थिति उत्पन्न करता है, लेकिन उनमें से अधिकांश (99.9 999% सटीक होने के लिए) अप्रासंगिक हैं। दिन के अंत में जो कुछ भी मायने रखता है वह यह तथ्य है कि 0 न्यूनतम परिणाम होना चाहिए। यदि आपका कोड सोचता है कि रूट 5 रूट 6 से बड़ा है, या रूट 234 रूट 235 से अधिक है तो यह अभी भी नहीं टूट जाएगा। विशेष रूप से पुनरावृत्ति के साथ रेस हालत होने की आवश्यकता होती है। 0. बाधाओं में से एक को पुनरावृत्ति में एक दूसरे के साथ दौड़ की स्थिति बहुत अधिक है। आखिरी वस्तु को पुन: संसाधित करने वाली बाधाओं में दौड़ की स्थिति वास्तव में काफी कम है।

4

क्यों आपका मूल कोड टूटा हुआ है अन्य उत्तरों की जांच करें, मैं इसे दोहराना नहीं चाहूंगा।

साझा स्थिति में कोई लेखन पहुंच नहीं होने पर मल्टीथ्रेडिंग सबसे आसान है। सौभाग्य से आपका कोड इस तरह लिखा जा सकता है। समांतर लिनक ऐसी परिस्थितियों में अच्छा हो सकता है, लेकिन कभी-कभी ओवरहेड बहुत बड़ा होता है। यह Min और Sqrt ऑपरेशन है, जो संभव है क्योंकि Sqrt होगा- बढ़ती जा रही है चारों ओर स्वैप करने के लिए तेज है अपने विशिष्ट समस्या में

double sqrt_min = myArr.AsParallel().Select(x=>Math.Sqrt(x)).Min(); 

:

आप करने के लिए अपने कोड को फिर से लिखने कर सकते हैं।

double sqrt_min = Math.Sqrt(myArr.AsParallel().Min()) 
संबंधित मुद्दे