कोशिश है-आखिरकार महंगा


14

कोड के मामले में जहां आपको एक फ़ंक्शन से बाहर निकलने से पहले संसाधन सफाई करना पड़ता है, क्या ऐसा करने के इन 2 तरीकों के बीच एक प्रमुख प्रदर्शन अंतर है।

  1. हर रिटर्न स्टेटमेंट से पहले संसाधन की सफाई

    void func()
    {
        login();
    
        bool ret = dosomething();
        if(ret == false)
        {
            logout();
            return;
        }
    
        ret = dosomethingelse();
        if(ret == false)
        {
            logout();
            return;
        }
    
        dootherstuff();
    
        logout();
    }
    
  2. अंत में ब्लॉक में संसाधन की सफाई

    void func()
    {
        login();
    
        try
        {
            bool ret = dosomething();
            if(ret == false)
                return;
    
            ret = dosomethingelse();
            if(ret == false)
                return;
    
            dootherstuff();
    
        }
        finally
        {
            logout();
        }
    }
    

मैंने नमूना कार्यक्रमों में कुछ बुनियादी परीक्षण किए और इसमें बहुत अंतर नहीं है। मैं ऐसा finallyकरने के तरीके को बहुत पसंद करता हूं - लेकिन मैं सोच रहा था कि क्या यह किसी बड़े प्रोजेक्ट में प्रदर्शन का कारण बनेगा।


3
यह वास्तव में उत्तर के रूप में पोस्ट करने लायक नहीं है, लेकिन नहीं। यदि आप जावा का उपयोग कर रहे हैं, जो अपवादों को डिफ़ॉल्ट त्रुटि से निपटने की रणनीति की अपेक्षा करता है, तो आपको कोशिश करनी चाहिए / पकड़ / अंत में - जिस पैटर्न का आप उपयोग कर रहे हैं, उसके लिए भाषा अनुकूलित है।
जोनाथन रिच

1
@ जोनाथनरिच: ऐसा कैसे?
हेलेम्

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

@mikeTheLiar - अगर आपका मतलब है कि मुझे लिखना चाहिए if(!cond), तो यह जावा है जिसने मुझे ऐसा किया है। C ++ में, यह है कि मैं दोनों बूलियन का कोड कैसे लिखता हूं और अन्य प्रकारों के लिए भी - यानी int x; if(!x)। चूँकि जावा मुझे केवल इसके लिए उपयोग करने की अनुमति देता है booleans, इसलिए मैंने जावा में if(cond)& का उपयोग करना पूरी तरह से बंद कर दिया है if(!cond)
user93353

1
@ user93353 जो मुझे दुखी करता है। मैं (someIntValue != 0)बूलियन का मूल्यांकन करने के बजाय तुलना करने के बजाय बहुत कुछ देखूंगा । यह मेरे लिए बदबू आ रही है, और जब मैं इसे जंगली में देखता हूं तो मैं तुरंत इसे रिफ्लेक्टर करता हूं।
माइकइलियार

जवाबों:


23

जैसा कि जावा अपवादों में कितनी धीमी गति से संकेत मिलता है? कोई यह देख सकता है कि try {} catch {}निर्बलता अपवाद के उदाहरण के भीतर है।

एक अपवाद बनाने से रनटाइम से पूरी कॉल स्टैक प्राप्त होगा और यह वह जगह है जहां खर्च होता है। यदि आप एक अपवाद नहीं बना रहे हैं, तो यह केवल समय की थोड़ी बहुत वृद्धि है।

इस प्रश्न में दिए गए उदाहरण में कोई अपवाद नहीं हैं, कोई भी उन्हें बनाने से किसी भी मंदी की उम्मीद नहीं करेगा - वे निर्मित नहीं हैं। इसके बजाय, यहाँ क्या है try {} finally {}अंत में ब्लॉक के भीतर संसाधन निपटने को संभालने के लिए है।

तो सवाल का जवाब देने के लिए, नहीं, एक try {} finally {}संरचना के भीतर कोई वास्तविक रनटाइम खर्च नहीं है जो अपवादों का उपयोग नहीं करता है (यह अनसुना नहीं है, जैसा कि देखा गया है)। क्या है संभवतः महंगा रखरखाव समय था जब एक कोड पढ़ता है और इस विशिष्ट नहीं कोड शैली को देखता है और सांकेतिक शब्दों में बदलनेवाला के आसपास उनके मन पाने के लिए है कि कुछ और करने के बाद इस विधि में होता है returnपिछले कॉल करने के लिए लौटने से पहले।


जैसा कि उल्लेख किया गया है, रखरखाव ऐसा करने के दोनों तरीकों के लिए एक तर्क है । रिकॉर्ड के लिए, विचार के बाद, मेरी प्राथमिकता अंततः दृष्टिकोण होगी।

किसी को एक नई भाषा संरचना सिखाने के रखरखाव समय पर विचार करें। देखना try {} finally {}कुछ ऐसा नहीं है जो अक्सर जावा कोड में दिखता है और इस तरह से लोगों को भ्रमित किया जा सकता है। जावा में कुछ अधिक उन्नत संरचनाओं को सीखने के लिए रखरखाव समय की डिग्री है जो लोग देखने से परिचित हैं।

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

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

पहले कायम रखने योग्य कोड लिखें, और अधिमानतः इस तरह से कि बग को बाद में लिखे जाने से रोका जा सके।


1
इस प्रकार एक-सुझाए गए संपादन ने कहा: "कोशिश / अंत में गारंटी देता है कि आपके पास रनटाइम अपवादों के बारे में अन्यथा नहीं होगा। आपको यह पसंद है या नहीं, कोई भी रेखा वस्तुतः एक अपवाद को फेंकने में सक्षम है" - मुझे: जो बिल्कुल सच नहीं है । प्रश्न में दी गई संरचना में कोई अतिरिक्त अपवाद नहीं है जो कोड के प्रदर्शन को धीमा कर देगा। गैर-कोशिश / अंत में ब्लॉक की तुलना में ब्लॉक के चारों ओर एक कोशिश / अंत में लपेटकर कोई अतिरिक्त प्रदर्शन प्रभाव नहीं है ।

2
कोशिश के अंत में इस उपयोग को समझने की तुलना में रखरखाव में और भी अधिक महंगा क्या हो सकता है, कई सफाई ब्लॉकों को बनाए रखना है। अब कम से कम आप जानते हैं कि यदि अतिरिक्त सफाई की आवश्यकता है, तो इसे लगाने के लिए केवल एक ही जगह है।
बार्ट वैन इनगेन शेनौ सेप

@BartvanIngenSchenau वास्तव में। एक कोशिश अंत में शायद इसे संभालने का सबसे अच्छा तरीका है, यह सिर्फ एक संरचना का आम नहीं है जिसे मैंने कोड में देखा है - लोगों को अंततः पकड़ने की कोशिश करने और सामान्य रूप से अपवाद को पकड़ने में समझने में काफी परेशानी होती है .. लेकिन कोशिश करें -फिनाली बिना कैच के? क्या? लोग वास्तव में इसे नहीं समझते हैं । जैसा कि आपने सुझाव दिया, भाषा संरचना को समझने से बेहतर है कि इसे टालने की कोशिश की जाए और चीजों को खराब तरीके से किया जाए।

मैं ज्यादातर यह जानना चाहता था कि आखिरकार कोशिश करना मुफ्त नहीं है। काश मैं लागत के बारे में आपके अतिरिक्त के लिए एक और उत्थान दे सकता।
बार्ट वैन इनगेन शेनौ सेप

5

/programming/299068/how-slow-are-java-exceptions

इस सवाल पर स्वीकृत जवाब एक कोशिश में एक फ़ंक्शन कॉल को पकड़ना दिखाता है एक नंगे फ़ंक्शन कॉल पर ब्लॉक की लागत 5% से कम है। वास्तव में अपवाद को फेंकना और पकड़ना गुब्बारे को रनटाइम के कारण 66x से अधिक नंगे फ़ंक्शन कॉल के लिए प्रेरित करता है। इसलिए यदि आप अपवाद डिज़ाइन को नियमित रूप से फेंकने की अपेक्षा करते हैं तो मैं इसे (ठीक से कुशल प्रदर्शन महत्वपूर्ण कोड में) से बचने की कोशिश करूंगा, हालांकि यदि असाधारण स्थिति दुर्लभ है तो यह कोई बड़ी बात नहीं है।


3
"अगर असाधारण स्थिति दुर्लभ है" - ठीक है वहाँ एक तना हुआ है। असाधारण का मतलब दुर्लभ है और यह ठीक है कि अपवादों का उपयोग कैसे किया जाना चाहिए। कभी भी डिजाइन या नियंत्रण प्रवाह का हिस्सा नहीं होना चाहिए।
जेसी सी। स्लाइसर

1
अपवाद व्यवहार में दुर्लभ नहीं हैं, यह सिर्फ आकस्मिक साइड इफेक्ट है। उदाहरण के लिए, यदि आपके पास बुरा यूआई लोग हैं, तो सामान्य प्रवाह की तुलना में अपवाद उपयोग मामले का प्रवाह अधिक बार हो सकता है
Esailija

2
प्रश्न के कोड में कोई अपवाद नहीं डाला जा रहा है।

2
@ JesseC.Slicer ऐसी भाषाएं हैं जहां उन्हें प्रवाह नियंत्रण के रूप में इस्तेमाल किया जाना असामान्य नहीं है। एक उदाहरण के रूप में जब अजगर में कुछ भी पुनरावृत्ति करता है तो इट्रेटर एक रोक अपवाद को फेंकता है जब यह किया जाता है। इसके अलावा OCaml में उनके मानक पुस्तकालय बहुत "फेंकने वाले खुश" प्रतीत होते हैं, यह बड़ी संख्या में ऐसी स्थितियों में फेंकता है जो दुर्लभ नहीं हैं (यदि आपके पास एक नक्शा है और कुछ ऐसा देखने की कोशिश करें जो उस नक्शे में मौजूद नहीं है जो इसे फेंकता है )।
पत्थरबाज़

@stonemal जैसा कि पायथन तानाशाह करता है, एक
कीरोर के

4

अनुकूलन के बजाय - यह सोचें कि आपका कोड क्या कर रहा है।

अंत में ब्लॉक को जोड़ना एक अलग कार्यान्वयन है - इसका मतलब है कि आप हर अपवाद पर लॉगआउट करेंगे।

विशेष रूप से - यदि लॉगिन अपवाद फेंकता है, तो आपके दूसरे फ़ंक्शन का व्यवहार आपके पहले से भिन्न होगा।

यदि लॉगिन और लॉगआउट वास्तव में फ़ंक्शन व्यवहार का हिस्सा नहीं हैं, तो मैं सुझाव दूंगा कि विधि को एक काम करना चाहिए और एक चीज़ अच्छी तरह से करनी चाहिए:

    void func()
    {
            bool ret = dosomething();
            if(ret == false)
                return;

            ret = dosomethingelse();
            if(ret == false)
                return;

            dootherstuff();

    }

और एक ऐसे फ़ंक्शन में होना चाहिए जो पहले से ही एक संदर्भ में एनकैप्सुलेटेड है जो लॉगिन / लॉगआउट का प्रबंधन करता है क्योंकि ये मूल रूप से आपके मुख्य कोड से अलग हैं।

आपकी पोस्ट को जावा के रूप में टैग किया गया है, जिससे मैं सुपर परिचित नहीं हूं, लेकिन .net में मैं इसके लिए एक ब्लॉक का उपयोग करूंगा:

अर्थात:

    using(var loginContext = CreateLoginContext()) 
    {
            // Do all your stuff
    }

और लॉगिन संदर्भ में एक डिस्पोज़ विधि है जो संसाधनों को लॉगआउट और साफ़ करेगा।

संपादित करें: मैंने वास्तव में सवाल का जवाब नहीं दिया!

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

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


1
अपने उत्तर को पूरा करने के लिए जावा 7 ने एक कोशिश के साथ संसाधन विवरण पेश किया है जो आपके .net usingनिर्माण के समान होगा , यह मानते हुए कि प्रश्न में संसाधन AutoCloseableइंटरफ़ेस को लागू करता है।
ज्येष्ठ

मैं इस retचर को भी हटा दूंगा, जिसे बाद में केवल एक पंक्ति में दो बार जांचा जाना है। बना लो if (dosomething() == false) return;
ott-- 15

सहमत थे लेकिन मैं ओपी कोड को जिस तरह से प्रदान किया गया था उसे रखना चाहता था।
माइकल

@ ott-- मुझे लगता है कि ओपी कोड उनके उपयोग के मामले का एक सरलीकरण है - उदाहरण के लिए, उनके पास कुछ अधिक हो सकता है ret2 = doSomethingElse(ret1), लेकिन यह प्रश्न के लिए प्रासंगिक नहीं है इसलिए इसे हटा दिया गया था।
इज़काता

if (dosomething() == false) ...बुरा कोड है। अधिक घुमक्कड़ का उपयोग करेंif (!dosomething()) ...
स्टीफन हील

1

मान लें: आप C # कोड में विकसित कर रहे हैं।

त्वरित उत्तर यह है कि कोशिश / अंत में ब्लॉक का उपयोग करने से कोई महत्वपूर्ण प्रदर्शन हिट नहीं है। जब आप अपवादों को फेंकते और पकड़ते हैं तो एक प्रदर्शन हिट होता है।

अपने स्वयं के लिए लंबे समय तक जवाब देखना है। यदि आप अंतर्निहित CIL कोड को देखते हैं ( जैसे रेड-गेट रिफ्लेक्टर तो आप अंतर्निहित CIL निर्देशों को देख सकते हैं और इस तरह से प्रभाव देख सकते हैं।


12
प्रश्न जावा को टैग किया गया है ।
जोचिम सॉर

अच्छी तरह से देखा गया! ;)
माइकल शॉ

3
इसके अलावा, तरीकों का पूंजीकरण नहीं किया गया है, हालांकि यह सिर्फ अच्छा स्वाद हो सकता है।
एरिक रेपेने

अभी भी एक अच्छा जवाब है अगर प्रश्न सी # :) था
फिल्लीएनजे

-2

के रूप में दूसरों को पहले ही उल्लेख किया, Ttese कोड अलग परिणाम है, यदि या तो होगा dosomethingelseया dootherstuffएक अपवाद फेंक देते हैं।

और हां, कोई भी फंक्शन कॉल अपवाद को फेंक सकता है, कम से कम ए StackOVerflowError! हालांकि इनका सही तरीके से संभालना काफी हद तक संभव है (जैसा कि किसी भी क्लीनअप फंक्शन को कहा जाता है, संभवत: यही समस्या होगी, कुछ मामलों में (जैसे कि उदाहरण के लिए ताले को लागू करना) यहां तक ​​कि सही ढंग से संभालना भी महत्वपूर्ण है ...


2
इससे पहले 6 जवाबों पर कुछ भी पर्याप्त नहीं लगता है
gnat
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.