2013-05-06 9 views
17

मैं सोच रहा हूं कि लॉक कोड का एक टुकड़ा मेरे कोड को धीमा कर सकता है भले ही कोड कभी निष्पादित न हो। यहां एक उदाहरण दिया गया है:लॉक कोड के कारण मंदी से कैसे बचें?

public void Test_PerformanceUnit() 
{ 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    Random r = new Random(); 
    for (int i = 0; i < 10000; i++) 
    { 
     testRand(r); 
    } 
    sw.Stop(); 
    Console.WriteLine(sw.ElapsedTicks); 
} 

public object testRand(Random r) 
{ 
    if (r.Next(1) > 10) 
    { 
     lock(this) { 
      return null; 
     } 
    } 
    return r; 
} 

यह कोड मेरी मशीन पर ~ 1300ms में चलता है। अगर हम लॉक ब्लॉक को हटाते हैं (लेकिन इसके शरीर को रखें), तो हमें 750 मिलीमीटर मिलेंगे। लगभग डबल, भले ही कोड कभी नहीं चलाया जाता है!

बेशक यह कोड कुछ भी नहीं करता है। मैंने इसे कक्षा में कुछ आलसी प्रारंभिक जोड़ते हुए देखा जहां कोड जांचता है कि ऑब्जेक्ट प्रारंभ होता है और यदि इसे प्रारंभ नहीं किया जाता है। समस्या यह है कि प्रारंभिक लॉक हो गया है और पहली कॉल के बाद भी सब कुछ धीमा हो जाता है।

मेरे प्रश्न हैं:

  1. हो रहा क्यों है?
  2. मंदी
+0

जब तक आप 'लॉक' का उपयोग करने का इरादा नहीं रखते हैं - मैं वास्तव में इसके बारे में चिंता नहीं करता। – James

+4

मुझे इसी तरह के परिणाम मिलते हैं, लेकिन एक टिक 100 * नैनो * -सेकंड है। दोनों रनों को ~ 0ms लेना चाहिए (यानी यदि आप 'sw.ElapseMilliseconds' प्रिंट करते हैं।) इस "मंदी" (~ 0.00006s) की संभावना इस तथ्य के कारण है कि' लॉक 'में' कोशिश/आखिरकार 'ब्लॉक शामिल है जो शायद जब विधि कहा जाता है तो सेटअप करें। लूप में 'testRand' की सामग्री डालने का प्रयास करें; आप उस बिंदु पर लगभग * नहीं * मंदी देखेंगे। – dlev

+0

क्या आपने 'आक्रामक इनलाइन' के साथ विधि को चिह्नित करने का प्रयास किया है? शायद लॉकिंग कोड ने सामान्य इनलाइनिंग के लिए विधि को बहुत बड़ा बना दिया। आईएन कोड के आकार के आधार पर .net JITter एक बदबूदार ह्युरिस्टिक का उपयोग करके रेखांकित करता है। – CodesInChaos

उत्तर

9

बारे में क्यों हो रहा है, यह टिप्पणी में चर्चा की गई से बचने के लिए कैसे: try ... finallylock द्वारा उत्पन्न की प्रारंभ की वजह यह है।


और यह मंदी से बचने के लिए, आप अवरोधित करने की सुविधा एक नई पद्धति के लिए, निकाल सकते हैं ताकि ताला तंत्र केवल प्रारंभ किया जाएगा यदि विधि वास्तव में कहा जाता है।

public object testRand(Random r) 
{ 
    if (r.Next(1) > 10) 
    { 
     return LockingFeature(); 
    } 
    return r; 
} 

private object LockingFeature() 
{ 
    lock (_lock) 
    { 
     return null; 
    } 
} 

और यहाँ मेरे बार (टिक में) कर रहे हैं:

your code, no lock : ~500 
your code, with lock : ~1200 
my code    : ~500 

संपादित करें:

मैं इस सरल कोड के साथ इसे करने की कोशिश मेरे परीक्षण कोड (थोड़ा की तुलना में धीमी चल कोई ताले वाला कोड) वास्तव में स्थैतिक तरीकों पर था, ऐसा प्रतीत होता है कि जब कोड किसी ऑब्जेक्ट के अंदर "अंदर" चलाया जाता है, तो समय समान होता है। मैंने उस समय के अनुसार समय तय किया।

+0

उत्तर के लिए धन्यवाद, यह वही था जो मैं खोज रहा था। मेरे परीक्षण में, आपका समाधान 'लॉक' इनलाइन की तुलना में तेज़ी से चला गया लेकिन केवल 'वापसी नल' ​​होने की तुलना में धीमा। कोड कोडलाइन से बचने के लिए मैंने 'लॉकिंग फीचर' विधि को 'आभासी' के रूप में परिभाषित किया और मुझे अपने प्रदर्शन का 100% वापस मिला। – pieroxy

+0

@ पियरोक्सी - आपके पहले परीक्षण के बारे में एक और बात यह है कि लॉक के साथ 'testRand() 'का संस्करण भी JIT तक ले जाता है। तो आप 'स्टॉपवॉच' शुरू होने से पहले 'टेस्टरैंड()' को केवल एक कॉल करके समीकरण से बाहर ले जा सकते हैं (जेआईटी कंपाइलर को गर्म करने के तरीके के रूप में, इसलिए बोलने के लिए)। यह अंतर को काफी हद तक कम करता है। फिर भी, ज़ोंको का कोड इस से निपटने का एक बहुत अच्छा तरीका है। –

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