2011-12-29 20 views
31

मैं बहुप्रचारित कार्यक्रमों में कैश विवाद के प्रभावों को चित्रित करने के लिए एक प्रोग्राम लिख रहा था। मेरा पहला कट long की सरणी बनाना था और दिखाएं कि आसन्न वस्तुओं को संशोधित करने से विवाद का कारण बनता है। कार्यक्रम यहाँ है।सरणी के समवर्ती संशोधन इतनी धीमी क्यों है?

const long maxCount = 500000000; 
const int numThreads = 4; 
const int Multiplier = 1; 
static void DoIt() 
{ 
    long[] c = new long[Multiplier * numThreads]; 
    var threads = new Thread[numThreads]; 

    // Create the threads 
    for (int i = 0; i < numThreads; ++i) 
    { 
     threads[i] = new Thread((s) => 
      { 
       int x = (int)s; 
       while (c[x] > 0) 
       { 
        --c[x]; 
       } 
      }); 
    } 

    // start threads 
    var sw = Stopwatch.StartNew(); 
    for (int i = 0; i < numThreads; ++i) 
    { 
     int z = Multiplier * i; 
     c[z] = maxCount; 
     threads[i].Start(z); 
    } 
    // Wait for 500 ms and then access the counters. 
    // This just proves that the threads are actually updating the counters. 
    Thread.Sleep(500); 
    for (int i = 0; i < numThreads; ++i) 
    { 
     Console.WriteLine(c[Multiplier * i]); 
    } 

    // Wait for threads to stop 
    for (int i = 0; i < numThreads; ++i) 
    { 
     threads[i].Join(); 
    } 
    sw.Stop(); 
    Console.WriteLine(); 
    Console.WriteLine("Elapsed time = {0:N0} ms", sw.ElapsedMilliseconds); 
} 

मैं दृश्य स्टूडियो 2010, रिलीज मोड में संकलित कार्यक्रम, .NET 4.0 लक्ष्य चल रहा हूँ, "कोई भी सीपीयू", और डीबगर संलग्न (Ctrl + F5) के बिना 64-बिट क्रम में मार डाला।

यह प्रोग्राम एक ही धागे के साथ, मेरे सिस्टम पर लगभग 1,700 एमएस में चलता है। दो धागे के साथ, इसमें 25 सेकंड लगते हैं। यह आंकड़ा कि अंतर कैश विवाद था, मैंने Multipler = 8 सेट किया और फिर से भाग गया। परिणाम 12 सेकंड है, इसलिए समस्या का कम से कम भाग था।

812 से अधिक Multiplier बढ़ाना प्रदर्शन में सुधार नहीं करता है।

तुलना के लिए, similar program that doesn't use an array में दो धागे के साथ केवल 2,200 एमएस लगता है जब चर निकट होते हैं। जब मैं चर को अलग करता हूं, तो दो थ्रेड संस्करण एक ही समय में एकल-थ्रेडेड संस्करण के रूप में चलता है।

यदि समस्या सरणी इंडेक्सिंग ओवरहेड थी, तो आप इसे एकल-थ्रेडेड संस्करण में दिखने की उम्मीद करेंगे। ऐसा लगता है कि सरणी को संशोधित करते समय कुछ प्रकार का पारस्परिक बहिष्कार चल रहा है, लेकिन मुझे नहीं पता कि यह क्या है।

जेनरेटेड आईएल को देखते हुए बहुत प्रबुद्ध नहीं है। न ही disassembly देख रहा था। डिस्सेप्लर रनटाइम लाइब्रेरी (मुझे लगता है) को कुछ कॉल दिखाता है, लेकिन मैं उनमें कदम रखने में सक्षम नहीं था।

मैं इन दिनों विंडबग या अन्य निम्न-स्तरीय डिबगिंग टूल के साथ कुशल नहीं हूं। यह वास्तव में एक लंबा समय रहा है क्योंकि मुझे उनकी आवश्यकता थी। तो मैं फंस गया हूँ।

अभी मेरी एकमात्र परिकल्पना यह है कि रनटाइम कोड प्रत्येक लेखन पर "गंदा" ध्वज सेट कर रहा है। ऐसा लगता है कि अगर ऐसा समझा जा रहा है तो एरे संशोधित होने पर अपवाद फेंकने के समर्थन के लिए ऐसा कुछ आवश्यक होगा। लेकिन मैं आसानी से स्वीकार करता हूं कि मेरे पास उस परिकल्पना का समर्थन करने के लिए कोई प्रत्यक्ष सबूत नहीं है।

क्या कोई मुझे बता सकता है कि इस बड़ी मंदी के कारण क्या हो रहा है?

+2

एफवाईआई सरणी फेंकने पर संशोधित होने पर फेंक नहीं देते हैं। (ऐसा करने के लिए एक कार्यान्वयन अपने अधिकारों के भीतर होगा, लेकिन व्यवहार में सीएलआर कार्यान्वयन ऐसा नहीं करता है।) –

+0

@Eric: जानकारी के लिए धन्यवाद। यह जानकर अच्छा लगा। –

उत्तर

36

आपको झूठी साझाकरण मिल गई है। मैंने इसके बारे में एक लेख लिखा है here

+0

दिलचस्प। किसी कारण से मैंने सोचा कि सरणी मेटाडेटा को सरणी (0] 'के निकट (या बहुत नज़दीकी) के बजाय वास्तविक सरणी सामग्री से अलग से संग्रहीत किया गया था। मुझे अपने कार्यक्रम में मोड बनाने दें और इसका परीक्षण करें। –

+0

यह वास्तव में समस्या थी। मैंने अपने प्रोग्राम को 'सी [गुणक * (i + 1)] तक पहुंचने के लिए संशोधित किया है और निष्पादन की गति अपेक्षित थी। धन्यवाद। –

+0

@ जिम मिशेल आपका स्वागत है - अच्छा सवाल! –

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