2011-02-01 13 views
15

अद्यतन: जैसा कि मुझे उम्मीद करनी चाहिए थी, इस प्रश्न के जवाब में समुदाय की ध्वनि सलाह "इसे मापने और देखने" थी। chibacity posted an answer कुछ वाकई अच्छे परीक्षणों के साथ जो मेरे लिए यह किया; इस बीच, मैंने अपना खुद का परीक्षण लिखा; और प्रदर्शन अंतर मैंने देखा कि वास्तव में इतनी बड़ी है कि I felt compelled to write a blog post about it.महंगा स्थानीय लोगों को बदलने के लिए थ्रेडस्टैटिक का उपयोग करना - अच्छा विचार?

हालांकि, मैं भी Hans's explanation को स्वीकार करना चाहिए कि ThreadStatic विशेषता वास्तव में मुक्त नहीं है और वास्तव में एक CLR सहायक विधि पर निर्भर करता है अपना जादू काम करने के लिए गया था। इससे यह स्पष्ट रूप से स्पष्ट हो जाता है कि क्या यह किसी भी मनमाना मामले में लागू करने के लिए उचित अनुकूलन होगा।

मेरे लिए अच्छी खबर यह है कि में मेरे मामले में, ऐसा लगता है कि यह एक बड़ा सुधार हुआ है।


मैं एक तरीका है जिसके (कई अन्य बातों के अलावा) में कुछ स्थानीय चर के लिए कुछ मध्यम आकार के सरणियों (~ 50 तत्वों) को दर्शाता है की है।

कुछ प्रोफाइलिंग के बाद मैंने इस विधि को प्रदर्शन बाधा के रूप में पहचाना है। ऐसा नहीं है कि विधि को कॉल करने में काफी लंबा समय लगता है; बल्कि, इसे कई बार कहा जाता है, बहुत जल्दी (सत्र में लाखों से लाखों बार, जो कई घंटे होंगे)। तो इसके प्रदर्शन में अपेक्षाकृत छोटे सुधार भी सार्थक होना चाहिए।

यह मेरे लिए हुआ कि शायद प्रत्येक कॉल पर एक नई सरणी आवंटित करने के बजाय, मैं [ThreadStatic] चिह्नित फ़ील्ड का उपयोग कर सकता हूं; जब भी विधि कहा जाता है, तो यह जांच करेगा कि क्या मौजूदा धागे पर फ़ील्ड प्रारंभ किया गया है, और यदि नहीं, तो इसे प्रारंभ करें। उस बिंदु से उसी थ्रेड पर सभी कॉलों पर उस बिंदु पर जाने के लिए तैयार एक सरणी होगी। यह एक अच्छा विचार की तरह प्रतीत होता है:

मेरा प्रश्न केवल यह है (। विधि सरणी अपने आप में हर तत्व है, तो होने सरणी में "बासी" तत्वों एक मुद्दा नहीं होना चाहिए initializes)? इस तरह ThreadStatic विशेषता का उपयोग करने के लिए समस्याएं हैं (यानी, स्थानीय चर के लिए नई वस्तुओं को तत्काल करने की लागत को कम करने के लिए प्रदर्शन अनुकूलन के रूप में) जिन्हें मुझे पता होना चाहिए? ThreadStatic फ़ील्ड का प्रदर्शन शायद महान नहीं है; उदाहरण के लिए, क्या इस सुविधा को संभव बनाने के लिए, पृष्ठभूमि में बहुत अधिक "सामान" हो रहा है, अपने स्वयं के लागत के सेट के साथ?

ऐसा नहीं है कि मैं भी रूप में सस्ते कुछ (?) एक 50-तत्व के रूप में अनुकूलन करने के लिए प्रयास करने के लिए गलत हूँ मेरे लिए काफी प्रशंसनीय भी है सरणी-और उस यदि ऐसा है तो है, निश्चित रूप से मुझे पता है-लेकिन जाने सामान्य सवाल अब भी आयोजित करता है।

+1

इसे आज़माएं और मापें। मुझे लगता है कि थ्रेड-लोकल आइटम तक पहुंच या तो मुक्त नहीं है, हालांकि फिर से आवंटन से सस्ता हो सकता है। – 9000

+0

इसे आज़माएं और इसे मापें। – BRampersad

+0

यदि आप .NET4 का उपयोग करने में सक्षम हैं तो [थ्रेडलोकल '] (http://msdn.microsoft.com/en-us/library/dd642243.aspx) भी न भूलें। जूरी अभी भी 'थ्रेडस्टैटिक' से बेहतर प्रदर्शन करता है या नहीं, लेकिन इसका उपयोग करना थोड़ा आसान है (और सही पाने के लिए)। मैं आपको 'थ्रेडलोकल ' पर विचार करने की सलाह दूंगा और इसे अपने मानक में शामिल करूँगा। – LukeH

उत्तर

5

मैंने एक साधारण बेंचमार्क किया है और ThreadStatic प्रश्न में वर्णित सरल पैरामीटर के लिए बेहतर प्रदर्शन करता है।

कई एल्गोरिदम, जो पुनरावृत्तियों की एक उच्च संख्या है के रूप में, मुझे लगता है यह संस्करण है जो नए सरणियों आवंटित के लिए यह की मौत हो गई जीसी भूमि के ऊपर का एक सीधा मामला है:

अद्यतन

परीक्षण के साथ कि

Iterations : 10,000,000 

Local ArrayRef   (- array iteration) : 330.17ms 
Local ArrayRef   (- array iteration) : 327.03ms 
Local ArrayRef   (- array iteration) : 1382.86ms 
Local ArrayRef   (- array iteration) : 1425.45ms 
Local ArrayRef   (- array iteration) : 1434.22ms 
TS CopyArrayRefLocal (- array iteration) : 107.64ms 
TS CopyArrayRefLocal (- array iteration) : 92.17ms 
TS CopyArrayRefLocal (- array iteration) : 92.42ms 
TS CopyArrayRefLocal (- array iteration) : 92.07ms 
TS CopyArrayRefLocal (- array iteration) : 92.10ms 
Local ArrayRef   (+ array iteration) : 1740.51ms 
Local ArrayRef   (+ array iteration) : 1647.26ms 
Local ArrayRef   (+ array iteration) : 1639.80ms 
Local ArrayRef   (+ array iteration) : 1639.10ms 
Local ArrayRef   (+ array iteration) : 1646.56ms 
TS CopyArrayRefLocal (+ array iteration) : 368.03ms 
TS CopyArrayRefLocal (+ array iteration) : 367.19ms 
TS CopyArrayRefLocal (+ array iteration) : 367.22ms 
TS CopyArrayRefLocal (+ array iteration) : 368.20ms 
TS CopyArrayRefLocal (+ array iteration) : 367.37ms 
TS TSArrayRef  (+ array iteration) : 360.45ms 
TS TSArrayRef  (+ array iteration) : 359.97ms 
TS TSArrayRef  (+ array iteration) : 360.48ms 
TS TSArrayRef  (+ array iteration) : 360.03ms 
TS TSArrayRef  (+ array iteration) : 359.99ms 
: न्यूनतम सरणी संदर्भ उपयोग मॉडल करने के लिए, के साथ साथ पिछले परीक्षण के अलावा ThreadStatic सरणी संदर्भ उपयोग जहां संदर्भ स्थानीय प्रतिलिपि बनाई गई सरणी के एक अतिरिक्त यात्रा में शामिल

कोड:

[ThreadStatic] 
private static int[] _array; 

[Test] 
public object measure_thread_static_performance() 
{ 
    const int TestIterations = 5; 
    const int Iterations = (10 * 1000 * 1000); 
    const int ArraySize = 50; 

    Action<string, Action> time = (name, test) => 
    { 
     for (int i = 0; i < TestIterations; i++) 
     { 
      TimeSpan elapsed = TimeTest(test, Iterations); 
      Console.WriteLine("{0} : {1:F2}ms", name, elapsed.TotalMilliseconds); 
     } 
    }; 

    int[] array = null; 
    int j = 0; 

    Action test1 =() => 
    { 
     array = new int[ArraySize]; 
    }; 

    Action test2 =() => 
    { 
     array = _array ?? (_array = new int[ArraySize]); 
    }; 

    Action test3 =() => 
    { 
     array = new int[ArraySize]; 

     for (int i = 0; i < ArraySize; i++) 
     { 
      j = array[i]; 
     } 
    }; 

    Action test4 =() => 
    { 
     array = _array ?? (_array = new int[ArraySize]); 

     for (int i = 0; i < ArraySize; i++) 
     { 
      j = array[i]; 
     } 
    }; 

    Action test5 =() => 
    { 
     array = _array ?? (_array = new int[ArraySize]); 

     for (int i = 0; i < ArraySize; i++) 
     { 
      j = _array[i]; 
     } 
    }; 

    Console.WriteLine("Iterations : {0:0,0}\r\n", Iterations); 
    time("Local ArrayRef   (- array iteration)", test1); 
    time("TS CopyArrayRefLocal (- array iteration)", test2); 
    time("Local ArrayRef   (+ array iteration)", test3); 
    time("TS CopyArrayRefLocal (+ array iteration)", test4); 
    time("TS TSArrayRef  (+ array iteration)", test5); 

    Console.WriteLine(j); 

    return array; 
} 

[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect")] 
private static TimeSpan TimeTest(Action action, int iterations) 
{ 
    Action gc =() => 
    { 
     GC.Collect(); 
     GC.WaitForFullGCComplete(); 
    }; 

    Action empty =() => { }; 

    Stopwatch stopwatch1 = Stopwatch.StartNew(); 

    for (int j = 0; j < iterations; j++) 
    { 
     empty(); 
    } 

    TimeSpan loopElapsed = stopwatch1.Elapsed; 

    gc(); 
    action(); //JIT 
    action(); //Optimize 

    Stopwatch stopwatch2 = Stopwatch.StartNew(); 

    for (int j = 0; j < iterations; j++) action(); 

    gc(); 

    TimeSpan testElapsed = stopwatch2.Elapsed; 

    return (testElapsed - loopElapsed); 
} 
+0

शायद यह एक यथार्थवादी तुलना करने के लिए सरणी का कुछ उपयोग होना चाहिए। –

+0

@ 500 अच्छा बिंदु - लेकिन क्या आप एक विशिष्ट समस्या देख सकते हैं? –

+0

मैंने अभी तक [थ्रेडस्टैटिक] का उपयोग नहीं किया है, इसलिए मैं कोई विशेषज्ञ नहीं हूं, लेकिन अप्रबंधित कोड में इसके बराबर प्रत्येक पहुंच के लिए ओवरहेड है। शायद [थ्रेडस्टैटिक] को स्थानीय उपयोग में इस्तेमाल करने से पहले इसे कम किया जा सकता है, लेकिन कुछ संख्याओं को देखना दिलचस्प होगा। –

2

this जैसे परिणामों से, थ्रेडस्टैटिक बहुत तेज दिखता है। मुझे यकीन नहीं है कि किसी के पास एक विशिष्ट उत्तर है यदि यह तेज़ है तो 50 तत्व सरणी को फिर से आवंटित करना। यही वह चीज है जो आपको स्वयं को बेंचमार्क करना होगा। :)

मैं कुछ हद तक फाड़ा हूं यदि यह "अच्छा विचार" है या नहीं। जब तक सभी कार्यान्वयन विवरण कक्षा के अंदर रखा जाता है, यह आवश्यक रूप से एक बुरा विचार नहीं है (आप वास्तव में नहीं चाहते कि कॉलर को इसके बारे में चिंता करनी पड़े), लेकिन जब तक बेंचमार्क ने इस विधि से प्रदर्शन लाभ नहीं दिखाया, तो मैं बस प्रत्येक बार सरणी आवंटित करना क्योंकि यह कोड को सरल और पढ़ने में आसान बनाता है। दो समाधानों की अधिक जटिल होने के कारण, मुझे इसे चुनने से पहले जटिलता से कुछ लाभ देखना होगा।

8

[थ्रेडस्टैटिक] नहीं मुफ्त दोपहर का भोजन है। परिवर्तक के लिए प्रत्येक पहुंच को जिटर द्वारा संकलित किए जाने के बजाय सीएलआर (JIT_GetThreadFieldAddr_Primitive/Objref) में एक सहायक फ़ंक्शन के माध्यम से जाना होगा। यह स्थानीय चर के लिए एक वास्तविक विकल्प भी नहीं है, रिकर्सन बाइट जा रहा है। आपको वास्तव में इसे स्वयं प्रोफाइल करना होगा, लूप में उस सीएलआर कोड के साथ perf guimstating perfible संभव नहीं है।

+1

आपको फ़ंक्शन कॉल के बाद केवल उस लागत का भुगतान करना होगा (सरणी को रेफरी करने और इसे वास्तविक स्थानीय में स्टोर करने के लिए) – Yuliy

+0

नहीं, यह कोई निःशुल्क लंच नहीं है। वस्तु संदर्भ अभी भी एक स्टब के माध्यम से चला जाता है। –

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

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