जब अपवाद नहीं फेंके जाते हैं तो क्या प्रदर्शन को प्रभावित करते हैं?


274

Microsoft कर्मचारी के साथ कोड की समीक्षा के दौरान हम एक try{}ब्लॉक के अंदर कोड के एक बड़े हिस्से में आए । उसने और एक आईटी प्रतिनिधि ने सुझाव दिया कि इससे कोड के प्रदर्शन पर प्रभाव पड़ सकता है। वास्तव में, उन्होंने सुझाव दिया कि अधिकांश कोड कोशिश / पकड़ने वाले ब्लॉक के बाहर होना चाहिए, और केवल महत्वपूर्ण अनुभागों की जांच होनी चाहिए। Microsoft कर्मचारी ने कहा कि एक आगामी श्वेत पत्र गलत कोशिश / पकड़ने वाले ब्लॉक के खिलाफ चेतावनी देता है।

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

मैं कोड की स्थिरता के बारे में नहीं पूछ रहा हूं, या यहां तक ​​कि सही अपवादों को भी संभाल रहा हूं (प्रश्न में कोड को पुन: फैक्टरिंग, कोई संदेह नहीं है)। मैं भी प्रवाह नियंत्रण के लिए अपवादों का उपयोग करने की बात नहीं कर रहा हूं, यह ज्यादातर मामलों में स्पष्ट रूप से गलत है। वे महत्वपूर्ण मुद्दे हैं (कुछ अधिक महत्वपूर्ण हैं), लेकिन यहां ध्यान केंद्रित नहीं किया गया है।

जब अपवाद नहीं फेंके जाते हैं तो प्रदर्शन को कैसे प्रभावित करते हैं ?


147
"वह जो प्रदर्शन के लिए शुद्धता का त्याग करेगा वह न ही योग्य है।"
जोएल कोएहॉर्न

16
कहा कि, प्रदर्शन के लिए शुद्धता की हमेशा जरूरत नहीं है।
दान डेविस ब्रैकेट

19
कैसे सरल जिज्ञासा के बारे में?
समंथा ब्रंहम

63
@ जोएल: शायद कोबी सिर्फ जिज्ञासा से बाहर जवाब जानना चाहता है। यह जानना कि क्या प्रदर्शन बेहतर या बुरा होगा, जरूरी नहीं कि वह अपने कोड के साथ कुछ भी करने जा रहा हो। अपने ज्ञान के लिए ज्ञान की खोज एक अच्छी बात नहीं है?
ल्यूक

6
यह जानने के लिए कि यह परिवर्तन करना है या नहीं, यहाँ एक अच्छा एल्गोरिथ्म है। सबसे पहले, सार्थक ग्राहक-आधारित प्रदर्शन लक्ष्य निर्धारित करें। दूसरा, पहले सही और स्पष्ट दोनों होने के लिए कोड लिखें। तीसरा, अपने लक्ष्यों के खिलाफ इसका परीक्षण करें। चौथा, यदि आप अपने लक्ष्यों को पूरा करते हैं, तो काम जल्दी खत्म करें और समुद्र तट पर जाएं। पांचवां, यदि आप अपने लक्ष्यों को पूरा नहीं करते हैं, तो कोड को खोजने के लिए प्रोफाइलर का उपयोग करें जो बहुत धीमा है। छठा, यदि वह कोड अनावश्यक अपवाद हैंडलर की वजह से बहुत धीमा होता है, तभी अपवाद हैंडलर को हटा दें। यदि नहीं, तो उस कोड को ठीक करें जो वास्तव में बहुत धीमा है। फिर चरण तीन पर वापस जाएं।
एरिक लिपर्ट

जवाबों:


203

इसे जाँचे।

static public void Main(string[] args)
{
    Stopwatch w = new Stopwatch();
    double d = 0;

    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        try
        {
            d = Math.Sin(1);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    w.Stop();
    Console.WriteLine(w.Elapsed);
    w.Reset();
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        d = Math.Sin(1);
    }

    w.Stop();
    Console.WriteLine(w.Elapsed);
}

आउटपुट:

00:00:00.4269033  // with try/catch
00:00:00.4260383  // without.

मिलीसेकंड में:

449
416

नया कोड:

for (int j = 0; j < 10; j++)
{
    Stopwatch w = new Stopwatch();
    double d = 0;
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        try
        {
            d = Math.Sin(d);
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

        finally
        {
            d = Math.Sin(d);
        }
    }

    w.Stop();
    Console.Write("   try/catch/finally: ");
    Console.WriteLine(w.ElapsedMilliseconds);
    w.Reset();
    d = 0;
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        d = Math.Sin(d);
        d = Math.Sin(d);
    }

    w.Stop();
    Console.Write("No try/catch/finally: ");
    Console.WriteLine(w.ElapsedMilliseconds);
    Console.WriteLine();
}

नए परिणाम:

   try/catch/finally: 382
No try/catch/finally: 332

   try/catch/finally: 375
No try/catch/finally: 332

   try/catch/finally: 376
No try/catch/finally: 333

   try/catch/finally: 375
No try/catch/finally: 330

   try/catch/finally: 373
No try/catch/finally: 329

   try/catch/finally: 373
No try/catch/finally: 330

   try/catch/finally: 373
No try/catch/finally: 352

   try/catch/finally: 374
No try/catch/finally: 331

   try/catch/finally: 380
No try/catch/finally: 329

   try/catch/finally: 374
No try/catch/finally: 334

24
क्या आप उन्हें उल्टे क्रम में आज़मा सकते हैं, साथ ही यह सुनिश्चित करने के लिए कि JIT संकलन का पूर्व पर कोई प्रभाव नहीं पड़ा है?
जोश जोर्डन

28
इस तरह के कार्यक्रम अपवाद हैंडलिंग के प्रभाव का परीक्षण करने के लिए शायद ही अच्छे उम्मीदवारों की तरह प्रतीत होते हैं, सामान्य प्रयास में जो भी हो रहा है उसका बहुत अधिक {} कैच {} ब्लॉक को अनुकूलित किया जाएगा। मैं उस पर दोपहर का भोजन करने के लिए बाहर हो सकता हूं ...
लोरेनव्स

30
यह एक डीबग बिल्ड है। JIT उन का अनुकूलन नहीं करता है।
बेन एम

7
यह बिल्कुल सच नहीं है, इसके बारे में सोचो। कितनी बार आप लूप में ट्राई कैच का उपयोग करते हैं? अधिकांश समय आप एक try.c में पाश का उपयोग करेगा
Athiwat Chunlakhan

9
वास्तव में? जब अपवाद नहीं फेंके जाते हैं तो प्रदर्शन को कैसे प्रभावित करते हैं?
बेन एम

105

ट्राई / कैच के साथ के लिए और बिना ट्राई / कैच सभी आँकड़े देखने के बाद, जिज्ञासा मुझे मजबूर देखने के लिए पीछे देखने के लिए दोनों ही मामलों के लिए उत्पन्न होता है। यहाँ कोड है:

सी#:

private static void TestWithoutTryCatch(){
    Console.WriteLine("SIN(1) = {0} - No Try/Catch", Math.Sin(1)); 
}

MSIL:

.method private hidebysig static void  TestWithoutTryCatch() cil managed
{
  // Code size       32 (0x20)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "SIN(1) = {0} - No Try/Catch"
  IL_0006:  ldc.r8     1.
  IL_000f:  call       float64 [mscorlib]System.Math::Sin(float64)
  IL_0014:  box        [mscorlib]System.Double
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
  IL_001e:  nop
  IL_001f:  ret
} // end of method Program::TestWithoutTryCatch

सी#:

private static void TestWithTryCatch(){
    try{
        Console.WriteLine("SIN(1) = {0}", Math.Sin(1)); 
    }
    catch (Exception ex){
        Console.WriteLine(ex);
    }
}

MSIL:

.method private hidebysig static void  TestWithTryCatch() cil managed
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Exception ex)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  ldstr      "SIN(1) = {0}"
    IL_0007:  ldc.r8     1.
    IL_0010:  call       float64 [mscorlib]System.Math::Sin(float64)
    IL_0015:  box        [mscorlib]System.Double
    IL_001a:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                  object)
    IL_001f:  nop
    IL_0020:  nop
    IL_0021:  leave.s    IL_002f //JUMP IF NO EXCEPTION
  }  // end .try
  catch [mscorlib]System.Exception 
  {
    IL_0023:  stloc.0
    IL_0024:  nop
    IL_0025:  ldloc.0
    IL_0026:  call       void [mscorlib]System.Console::WriteLine(object)
    IL_002b:  nop
    IL_002c:  nop
    IL_002d:  leave.s    IL_002f
  }  // end handler
  IL_002f:  nop
  IL_0030:  ret
} // end of method Program::TestWithTryCatch

मैं IL में विशेषज्ञ नहीं हूं, लेकिन हम देख सकते हैं कि एक स्थानीय अपवाद वस्तु चौथी लाइन पर बनाई गई है, .locals init ([0] class [mscorlib]System.Exception ex)उसके बाद चीजें बिना लाइन / सत्रह तक पकड़ने की विधि के समान हैं IL_0021: leave.s IL_002f। यदि कोई अपवाद होता है, तो नियंत्रण लाइन पर IL_0025: ldloc.0कूद जाता है अन्यथा हम लेबल IL_002d: leave.s IL_002fऔर फ़ंक्शन रिटर्न पर कूद जाते हैं ।

मैं सुरक्षित रूप से यह मान सकता हूं कि यदि कोई अपवाद नहीं होता है, तो यह अपवाद वस्तुओं को रखने के लिए स्थानीय चर बनाने का ओवरहेड है और केवल एक कूदने का निर्देश है।


33
खैर, IL में C # के समान नोटेशन में एक try / कैच ब्लॉक शामिल है, इसलिए यह वास्तव में यह नहीं दर्शाता है कि पर्दे के पीछे एक try / कैच का मतलब कितना ओवरहेड है! बस यह है कि आईएल बहुत अधिक नहीं जोड़ता है, इसका मतलब यह नहीं है क्योंकि यह संकलित असेंबली कोड में कुछ जोड़ा नहीं गया है। IL सभी .NET भाषाओं का एक सामान्य प्रतिनिधित्व है। यह मशीन कोड नहीं है!
खौफ

64

नहीं, यदि तुच्छ अनुकूलन वास्तव में आपके प्रोग्राम पर एक औसत दर्जे का प्रभाव डालता है, तो शायद आपको पहली बार में .NET का उपयोग नहीं करना चाहिए।


10
यह एक उत्कृष्ट बिंदु है - हमारी सूची में अन्य वस्तुओं की तुलना में, यह एक घटा होना चाहिए। हमें सही व्यवहार करने के लिए बुनियादी भाषा सुविधाओं पर भरोसा करना चाहिए, और जो हम नियंत्रित कर सकते हैं उसे अनुकूलित करें (sql, indexes, एल्गोरिदम)।
कोबी

3
तंग छोरों साथी के बारे में सोचो। लूप का उदाहरण दें जहां आप गेम सर्वर में सॉकेट डेटा स्ट्रीम से ऑब्जेक्ट पढ़ते हैं और डी-सीरियल करते हैं और जितना संभव हो उतना निचोड़ने की कोशिश करते हैं। तो आप बाइनरीफ़ॉर्मेटर के बजाय ऑब्जेक्ट सीरियललाइज़ेशन के लिए मैसेजपैक करें, और केवल बाइट सरणियों, आदि बनाने के बजाय ArrayPool <बाइट> का उपयोग करें ... इन परिदृश्यों में एकाधिक (शायद नेस्टेड) ​​का क्या प्रभाव है, तंग लूप के भीतर ब्लॉक को पकड़ने का प्रयास करें। कुछ ऑप्टिमाइज़ेशन को कंपाइलर द्वारा छोड़ दिया जाएगा, अपवाद चर Gen0 GC को भी जाता है। मैं केवल इतना कह रहा हूं कि "कुछ" परिदृश्य हैं जहां हर चीज का प्रभाव पड़ता है।
tcwicks

35

.NET अपवाद मॉडल की व्यापक व्याख्या।

रिको मरिअनी का प्रदर्शन टिडबिट्स: अपवाद लागत: कब फेंकना है और कब नहीं

पहली तरह की लागत आपके कोड में अपवाद से निपटने की स्थिर लागत है। प्रबंधित अपवाद वास्तव में यहाँ तुलनात्मक रूप से अच्छा है, जिसके द्वारा मेरा मतलब है कि C ++ की तुलना में स्थैतिक लागत बहुत कम हो सकती है। ऐसा क्यों है? ठीक है, स्थैतिक लागत वास्तव में दो प्रकार के स्थानों में होती है: सबसे पहले, उन निर्माणों के लिए कोड / अंत / पकड़ने / फेंकने की वास्तविक साइटें जहां कोड है। दूसरा, अनमैंग्ड कोड में, उन सभी वस्तुओं पर नज़र रखने से जुड़ी हुई चोरी की लागत है जो इस घटना में नष्ट हो जानी चाहिए कि एक अपवाद फेंक दिया गया है। इसमें काफी मात्रा में सफाई के तर्क मौजूद होने चाहिए और डरपोक हिस्सा यह है कि यहां तक ​​कि कोड भी नहीं है '

दमित्री ज़स्लावस्की:

क्रिस ब्रुम के नोट के अनुसार: इस तथ्य से संबंधित एक लागत भी है कि कैच की उपस्थिति में कुछ अनुकूलन जेआईटी द्वारा नहीं किए जा रहे हैं


1
C ++ के बारे में यह है कि मानक पुस्तकालय का एक बहुत बड़ा हिस्सा अपवादों को फेंक देगा। उनके बारे में कुछ भी वैकल्पिक नहीं है। आपको अपनी वस्तुओं को किसी प्रकार की अपवाद नीति के साथ डिजाइन करना होगा, और एक बार जब आप ऐसा कर लेंगे कि कोई अधिक चोरी की लागत नहीं है।
डेविड थॉर्नले

रीको मैरियानी के दावे देशी सी ++ के लिए पूरी तरह से गलत हैं। "स्थिर लागत C ++ में कहने की तुलना में बहुत कम हो सकती है" - यह केवल सच नहीं है। हालांकि, मुझे यकीन नहीं है कि 2003 में जब लेख लिखा गया था तब अपवाद तंत्र डिजाइन क्या था। C ++ की वास्तव में कोई कीमत नहीं है जब अपवाद नहीं फेंके जाते हैं, चाहे आपके पास कितने भी प्रयास / कैच ब्लॉक हों और वे कहां हैं।
बीजोवेके

1
@BJovke C ++ "शून्य लागत अपवाद हैंडलिंग" का अर्थ केवल यह है कि अपवाद नहीं फेंके जाने पर कोई रन-टाइम लागत नहीं है, लेकिन अपवादों पर सभी सफाई कोड कॉलिंग डिस्ट्रक्टर्स के कारण अभी भी एक प्रमुख कोड-आकार की लागत है। इसके अलावा, जबकि सामान्य कोड पथ पर कोई अपवाद-विशिष्ट कोड उत्पन्न नहीं किया जा रहा है, लागत अभी भी वास्तव में शून्य नहीं है, क्योंकि अपवाद की संभावना अभी भी अनुकूलक को प्रतिबंधित करती है (जैसे कि अपवाद के मामले में आवश्यक सामान को रहने की आवश्यकता है आसपास कहीं -> मूल्यों को कम आक्रामक रूप से त्याग दिया जा सकता है -> कम कुशल रजिस्टर आवंटन)
डैनियल

24

बेन एम से उदाहरण में संरचना अलग है । यह आंतरिक forलूप के अंदर ओवरहेड बढ़ाया जाएगा जो दो मामलों के बीच अच्छी तुलना नहीं करेगा।

निम्नलिखित तुलना के लिए और अधिक सटीक है जहां पूरे कोड को जांचने के लिए (चर घोषणा सहित) कोशिश / कैच ब्लॉक के अंदर है:

        for (int j = 0; j < 10; j++)
        {
            Stopwatch w = new Stopwatch();
            w.Start();
            try { 
                double d1 = 0; 
                for (int i = 0; i < 10000000; i++) { 
                    d1 = Math.Sin(d1);
                    d1 = Math.Sin(d1); 
                } 
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString()); 
            }
            finally { 
                //d1 = Math.Sin(d1); 
            }
            w.Stop(); 
            Console.Write("   try/catch/finally: "); 
            Console.WriteLine(w.ElapsedMilliseconds); 
            w.Reset(); 
            w.Start(); 
            double d2 = 0; 
            for (int i = 0; i < 10000000; i++) { 
                d2 = Math.Sin(d2);
                d2 = Math.Sin(d2); 
            } 
            w.Stop(); 
            Console.Write("No try/catch/finally: "); 
            Console.WriteLine(w.ElapsedMilliseconds); 
            Console.WriteLine();
        }

जब मैंने बेन एम से मूल परीक्षण कोड चलाया , तो मैंने डिबग और रिले कॉन्फ़िगरेशन दोनों में अंतर देखा।

इस संस्करण में, मैंने डिबग संस्करण (वास्तव में अन्य संस्करण की तुलना में अधिक) में अंतर देखा, लेकिन रिलीज संस्करण में यह कोई अंतर नहीं था।

Conclution :
इन परीक्षण के आधार पर, मुझे लगता है कि हम कह सकते हैं कि ट्राई / कैच करता है प्रदर्शन पर एक छोटा सा प्रभाव पड़ता है।

संपादित करें:
मैंने लूप मूल्य को 10000000 से बढ़ाकर 1000000000 करने की कोशिश की, और रिलीज़ में कुछ अंतर पाने के लिए फिर से भाग गया, और परिणाम यह था:

   try/catch/finally: 509
No try/catch/finally: 486

   try/catch/finally: 479
No try/catch/finally: 511

   try/catch/finally: 475
No try/catch/finally: 477

   try/catch/finally: 477
No try/catch/finally: 475

   try/catch/finally: 475
No try/catch/finally: 476

   try/catch/finally: 477
No try/catch/finally: 474

   try/catch/finally: 475
No try/catch/finally: 475

   try/catch/finally: 476
No try/catch/finally: 476

   try/catch/finally: 475
No try/catch/finally: 476

   try/catch/finally: 475
No try/catch/finally: 474

आप देखते हैं कि परिणाम असंगत है। कुछ मामलों में Try / Catch का उपयोग करने वाला संस्करण वास्तव में तेज़ है!


1
मैंने यह भी देखा है, कभी-कभी यह कोशिश / पकड़ के साथ तेज होता है। मैंने इसे बेन के जवाब पर टिप्पणी की है। हालांकि, 24 मतदाताओं के विपरीत, मुझे इस तरह का बेंचमार्किंग पसंद नहीं है, मुझे नहीं लगता कि यह एक अच्छा संकेत है। इस मामले में कोड तेज है, लेकिन क्या यह हमेशा रहेगा?
कोबी

5
क्या यह साबित नहीं होता है कि आपकी मशीन एक ही समय में कई अन्य कार्य कर रही है? बीता हुआ समय कभी भी अच्छा उपाय नहीं होता है, आपको एक प्रोफ़ाइलर का उपयोग करने की ज़रूरत होती है जो प्रोसेसर के समय को रिकॉर्ड करता है, बीता हुआ समय नहीं।
कॉलिन डेसमंड

2
@ कोबी: मैं सहमत हूं कि यह बेंचमार्क करने का सबसे अच्छा तरीका नहीं है अगर आप इसे एक प्रमाण के रूप में प्रकाशित करने जा रहे हैं कि आपका कार्यक्रम अन्य या किसी चीज़ की तुलना में तेज़ी से चलता है, लेकिन आपको एक डेवलपर के रूप में एक दूसरे से बेहतर प्रदर्शन करने का संकेत दे सकता है । इस मामले में, मुझे लगता है कि हम कह सकते हैं कि अंतर (कम से कम रिलीज़ कॉन्फ़िगरेशन के लिए) आग्नेय है।
खौफ

1
आप try/catchयहां टाइमिंग नहीं कर रहे हैं। आप 12 कोशिश कर रहे हैं / 10M छोरों के खिलाफ प्रवेश-महत्वपूर्ण-सेक्शन को पकड़ सकते हैं । लूप का शोर किसी भी प्रभाव को मिटा देगा जो कोशिश / पकड़ है। यदि इसके बजाय आप तंग पाश के अंदर की कोशिश / पकड़ डालते हैं, और साथ / बिना तुलना करते हैं, तो आप कोशिश / पकड़ की लागत के साथ समाप्त हो जाएंगे। (कोई शक नहीं, इस तरह की कोडिंग आम तौर पर अच्छा अभ्यास नहीं है, लेकिन अगर आप किसी निर्माण के ओवरहेड को समय देना चाहते हैं, तो आप इसे कैसे करते हैं)। आजकल, बेंचमार्कडॉटनेट विश्वसनीय निष्पादन समय के लिए उपकरण है।
हाबिल

15

मैंने try..catchएक तंग पाश में एक के वास्तविक प्रभाव का परीक्षण किया , और यह किसी भी सामान्य स्थिति में प्रदर्शन की चिंता के लिए अपने आप से बहुत छोटा है।

यदि लूप बहुत कम काम करता है (मेरे परीक्षण में मैंने किया था x++), आप अपवाद हैंडलिंग के प्रभाव को माप सकते हैं। अपवाद हैंडलिंग के साथ लूप को चलने में लगभग दस गुना अधिक समय लगा।

यदि लूप कुछ वास्तविक कार्य करता है (मेरे परीक्षण में मुझे Int32.Parse विधि कहा जाता है), अपवाद हैंडलिंग का औसत दर्जे का होने के लिए बहुत कम प्रभाव पड़ता है। छोरों के आदेश की अदला-बदली करके मुझे बहुत बड़ा अंतर मिला ...


11

प्रयास करें कि कैच ब्लॉक का प्रदर्शन पर एक नगण्य प्रभाव पड़ता है, लेकिन अपवाद थ्रोइंग बहुत बड़ा हो सकता है, संभवतः यह वह जगह है जहां आपका सहकर्मी भ्रमित था।


8

प्रदर्शन पर प्रभाव / पकड़ने का प्रयास।

लेकिन इसका बहुत बड़ा असर नहीं हुआ। कोशिश / पकड़ जटिलता आम तौर पर ओ (1) है, एक साधारण असाइनमेंट की तरह, सिवाय जब वे एक लूप में रखे जाते हैं। इसलिए आपको उन्हें बुद्धिमानी से उपयोग करना होगा।

यहाँ कोशिश / पकड़ने के प्रदर्शन के बारे में एक संदर्भ है (हालांकि इसकी जटिलता की व्याख्या नहीं की गई है, लेकिन यह निहित है)। थ्रो फेयर एक्सेप्शन सेक्शन पर नज़र डालें


3
जटिलता हे (1) यह बहुत ज्यादा मतलब नहीं है। उदाहरण के लिए यदि आप एक कोड सेक्शन को कहते हैं, जिसे ट्राइ-कैच (या आप एक लूप का उल्लेख करते हैं) के साथ बहुत बार कहा जाता है, तो ओ (1) एस अंत में एक औसत दर्जे की संख्या में जोड़ सकता है।
सेसाबा तोथ

6

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

Action q;
double thing1()
  { double total; for (int i=0; i<1000000; i++) total+=1.0/i; return total;}
double thing2()
  { q=null; return 1.0;}
...
x=thing1();     // statement1
x=thing2(x);    // statement2
doSomething(x); // statement3

कंपाइलर कथन 1 को इस तथ्य के आधार पर अनुकूलित करने में सक्षम हो सकता है कि कथन 2 को कथन 3 से पहले निष्पादित करने की गारंटी है। यदि कंपाइलर यह पहचान सकता है कि thing1 का कोई साइड-इफेक्ट नहीं है और thing2 वास्तव में x का उपयोग नहीं करता है, तो यह thing1 को पूरी तरह से छोड़ सकता है। यदि [जैसा कि इस मामले में] thing1 महंगा था, कि एक प्रमुख अनुकूलन हो सकता है, हालांकि मामले 1 जहां महंगा है, वे भी हैं जो संकलक कम से कम ऑप्टिमाइज़ होने की संभावना है। मान लीजिए कि कोड बदल दिए गए हैं:

x=thing1();      // statement1
try
{ x=thing2(x); } // statement2
catch { q(); }
doSomething(x);  // statement3

अब उन घटनाओं का एक क्रम मौजूद है जहाँ कथन 3 बिना कथन 2 को निष्पादित कर सकता है। यहां तक ​​कि अगर कोड में कुछ भी thing2एक अपवाद को नहीं फेंक सकता है, तो यह संभव होगा कि एक और थ्रेड एक Interlocked.CompareExchangeनोटिस का उपयोग कर सकता है जो qइसे मंजूरी दे दी गई थी Thread.ResetAbortऔर फिर इसे सेट करने के लिए Thread.Abort()पहले एक स्टेटमेंट 2 लिखा था x। तब [प्रतिनिधि के माध्यम से ] catchनिष्पादित करेगा , निष्पादन को कथन 3 के साथ जारी रखने की अनुमति देगा। ऐसी घटनाओं का क्रम निश्चित रूप से असाधारण रूप से असंभव होगा, लेकिन कोड जनरेट करने के लिए एक कंपाइलर की आवश्यकता होती है जो इस तरह की अनुचित घटनाओं के होने पर भी विनिर्देश के अनुसार काम करता है।Thread.ResetAbort()q

सामान्य तौर पर, कंपाइलर कॉम्प्लेक्स बिट्स की तुलना में कोड के सरल बिट्स को छोड़ने के अवसरों को नोटिस करने की बहुत अधिक संभावना है, और इस तरह यह एक दुर्लभ / कोशिश के लिए दुर्लभ होगा यदि अपवाद कभी भी फेंके नहीं जाते हैं तो प्रदर्शन को प्रभावित कर सकता है। फिर भी, कुछ परिस्थितियाँ ऐसी होती हैं जहाँ एक कोशिश / कैच ब्लॉक का अस्तित्व अनुकूलन को रोक सकता है - लेकिन कोशिश / पकड़ने के लिए - कोड को तेज़ी से चलाने की अनुमति देता है।


5

यद्यपि " रोकथाम , हैंडलिंग से बेहतर है ", प्रदर्शन और दक्षता के परिप्रेक्ष्य में हम पूर्व-संस्करण पर कोशिश को पकड़ सकते हैं। नीचे दिए गए कोड पर विचार करें:

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 1; i < int.MaxValue; i++)
{
    if (i != 0)
    {
        int k = 10 / i;
    }
}
stopwatch.Stop();
Console.WriteLine($"With Checking: {stopwatch.ElapsedMilliseconds}");
stopwatch.Reset();
stopwatch.Start();
for (int i = 1; i < int.MaxValue; i++)
{
    try
    {
        int k = 10 / i;
    }
    catch (Exception)
    {

    }
}
stopwatch.Stop();
Console.WriteLine($"With Exception: {stopwatch.ElapsedMilliseconds}");

यहाँ परिणाम है:

With Checking: 20367
With Exception: 13998

4

कैसे ब्लॉक / काम को पकड़ने की कोशिश करते हैं और कैसे कुछ कार्यान्वयन उच्च ओवरहेड है, और कुछ शून्य ओवरहेड है, जब कोई अपवाद नहीं होता है की चर्चा के लिए प्रयास / कैच कार्यान्वयन पर चर्चा देखें । विशेष रूप से, मुझे लगता है कि विंडोज 32 बिट कार्यान्वयन में उच्च ओवरहेड है, और 64 बिट कार्यान्वयन नहीं है।


मैंने जो बताया वह अपवादों को लागू करने के लिए दो अलग-अलग दृष्टिकोण हैं। दृष्टिकोण समान रूप से C ++ और C #, साथ ही प्रबंधित / अप्रबंधित कोड पर लागू होते हैं। एमएस ने अपने सी # के लिए किन लोगों को चुना है, मुझे ठीक से पता नहीं है, लेकिन एमएस द्वारा प्रदान की गई मशीन-स्तरीय अनुप्रयोगों की अपवाद-हैंडलिंग वास्तुकला तेजी से योजना का उपयोग करती है। अगर 64 बिट्स के लिए C # कार्यान्वयन इसका उपयोग नहीं करता है तो मुझे थोड़ा आश्चर्य होगा।
ईरा बाक्सटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.