2010-05-16 14 views
25

क्या दक्षता के अनुसार छोरों लेखन के पसंदीदा तरीका है: रास्ता एक)क्या मैं अनुकूलित कर सकता हूं या संकलक को ऐसा करने देता हूं?

/*here I'm hoping that compiler will optimize this 
code and won't be calling size every time it iterates through this loop*/ 
    for (unsigned i = firstString.size(); i < anotherString.size(), ++i) 
    { 
    //do something 
    } 

या हो सकता है मैं इसे इस तरह से करना चाहिए: रास्ता ख)

unsigned first = firstString.size(); 
unsigned second = anotherString.size(); 

और अब मैं लिख सकते हैं :

for (unsigned i = first; i < second, ++i) 
    { 
    //do something 
    } 

दूसरा तरीका मुझे दो कारणों से बदतर विकल्प की तरह लगता है: स्कोप प्रदूषण और क्रियापदता यह सुनिश्चित करने का लाभ है कि आकार() प्रत्येक वस्तु के लिए एक बार लागू किया जाएगा।
अपने उत्तरों के लिए तत्पर हैं।

+8

ध्यान दें कि 'firstString.size()' केवल एक बार बुलाया जाएगा, ताकि इसे लूप से बाहर ले जाने योग्य नहीं है। –

+0

या आप iterators का उपयोग कर सकते हैं और इस समस्या से पूरी तरह से बचें। –

+3

"हस्ताक्षरित" का उपयोग न करें; इस बात की कोई गारंटी नहीं है कि "std :: size_t" सभी प्लेटफ़ॉर्म पर हस्ताक्षरित जैसा ही होगा (उदा। यह "लंबे समय तक हस्ताक्षरित" हो सकता है)। इसके बजाय, "std :: size_t" का उपयोग करें। –

उत्तर

62

मैं आम तौर पर इस कोड के रूप में लिखें।

इस iterators के लिए विशेष रूप से उपयोगी है:

for(some_generic_type<T>::forward_iterator it = collection.begin(), end = collection.end(); 
    it != end; ++it) { 
    // do something with *it 
} 
+18

11 साल में ऐसा करने के बारे में कभी सोचने के लिए खुद को लात मारना! –

+0

+1 किसी भी तरह से मैंने हमेशा इस तथ्य को याद किया है कि आप लूप में एकाधिक चर प्रारंभ कर सकते हैं। – NotMe

+0

इटरेटर के साथ बहुत आसान है, अगर आप for_each का उपयोग नहीं करना चाहते हैं;) – knittl

15

मैं पहले पहले संस्करण का उपयोग करता हूं, क्योंकि यह क्लीनर और टाइप करने में आसान लगता है। फिर आप यह देखने के लिए प्रोफ़ाइल कर सकते हैं कि कुछ और अनुकूलित करने की आवश्यकता है या नहीं।

लेकिन मुझे संदेह है कि पहला संस्करण एक उल्लेखनीय प्रदर्शन ड्रॉप का कारण बन जाएगा। कंटेनर को लागू करता है तो size() इस तरह:

inline size_t size() const 
{ 
    return _internal_data_member_representing_size; 
} 

तो संकलक समारोह इनलाइन करने के लिए, eliding समारोह कॉल सक्षम होना चाहिए। मानक कंटेनर के मेरे कंपाइलर का कार्यान्वयन यह सब करता है।

3

यह उन चीजों में से एक है जिसे आपको स्वयं परीक्षण करना चाहिए। लूप 10,000 या यहां तक ​​कि 100,000 पुनरावृत्तियों को चलाएं और देखें कि क्या अंतर है, यदि कोई है, तो मौजूद है।

आपको वह सब कुछ बताना चाहिए जो आप जानना चाहते हैं।

17

सामान्य रूप से, कंपाइलर इसे करने दें। सूक्ष्म अनुकूलन के बजाय आप जो कर रहे हैं उसकी एल्गोरिदमिक जटिलता पर फ़ोकस करें।

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

+7

+1 यह इंगित करने के लिए कि कोड के दो स्निपेट एक ही ऑपरेशन नहीं करते हैं। –

7

एक अच्छा कंपाइलर आपके कोड को कैसे अनुकूलित करेगा? बिलकुल नहीं, क्योंकि यह सुनिश्चित नहीं हो सकता है कि size() का कोई दुष्प्रभाव है। यदि size() पर आपके साइड इफेक्ट्स पर कोई साइड इफेक्ट्स था, तो वे अब संभावित कंपाइलर ऑप्टिमाइज़ेशन के बाद चले जाएंगे।

इस प्रकार का अनुकूलन वास्तव में एक कंपाइलर के परिप्रेक्ष्य से सुरक्षित नहीं है, आपको इसे स्वयं करने की आवश्यकता है। अपने आप को करने का मतलब यह नहीं है कि आपको दो अतिरिक्त स्थानीय चर पेश करने की आवश्यकता है। आकार के कार्यान्वयन के आधार पर, यह एक ओ (1) ऑपरेशन हो सकता है। यदि आकार को इनलाइन भी घोषित किया गया है, तो आप स्थानीय कॉल एक्सेस के रूप में अच्छी तरह से size() पर कॉल करने के लिए फ़ंक्शन कॉल भी छोड़ देंगे।

+3

आकार() होने के बाद एक ओ (1) ऑपरेशन म्यूटेबल तारों के साथ भी आसान है। – sepp2k

+0

@ sepp2k: हाँ, लेकिन स्ट्रिंग की सामग्री में बदलाव के बाद आपको किसी भी तरह आकार का आलसी मूल्यांकन करने की आवश्यकता है (यानी मैं एक गंदे झंडे का उपयोग कर रहा हूं)। इस प्रकार यह _always_ ओ (1) नहीं है, जबकि अपरिवर्तनीय तार सृजन पर उनके आकार की गणना कर सकते हैं। फिर भी, यह इस प्रश्न के लिए अप्रासंगिक है। –

+2

@ जोहान्स रुडॉल्फ: क्या मैं? प्रत्येक विनाशकारी ऑपरेशन के साथ लंबाई को अपडेट करने में क्या गलत है? जैसे आकार एन की एक स्ट्रिंग को जोड़ते समय, 'लंबाई + = एन'। क्या कोई ऑपरेशन है जहां आप ऑपरेशन करते समय ओ (1) समय में आसानी से लंबाई अपडेट नहीं कर सकते? (हाँ, यह अप्रासंगिक है, बस पूछ रहा है)। – sepp2k

1

यहां मैं इसे कैसे देखता हूं। प्रदर्शन और शैली दोनों महत्वपूर्ण हैं, और आपको दोनों के बीच चयन करना होगा।

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

6

Don't pre-optimize आपका कोड। यदि आपके पास कोई प्रदर्शन समस्या है, तो इसे खोजने के लिए एक प्रोफाइलर का उपयोग करें, अन्यथा आप विकास का समय बर्बाद कर रहे हैं। बस सबसे सरल/साफ कोड लिखें जो आप कर सकते हैं।

/* i and size are local to the loop */ 
for (size_t i = firstString.size(), size = anotherString.size(); i < size; ++i) { 
    //do something 
} 

इस तरह से मैं माता पिता के दायरे अपवित्र नहीं करते हैं और प्रत्येक पाश यात्रा के लिए anotherString.size() बुला से बचने:

+0

बनाने में सहायता करता है आम तौर पर, मैं कहूंगा कि स्वच्छतम कोड लिखने से आप ऑप्टिमाइज़र के लिए चीजों को आसान बना सकते हैं। –

+0

इस जवाब का लिंक वर्तमान में एक ब्लॉग को इंगित करता है जिसमें सचमुच कोई लेख नहीं है। – cHao

2

मैं आशा करती हूं कि संकलक इस अनुकूलित करेंगे ...

आप नहीं करना चाहिए। एक सी ++ संकलक का अनुकूलन करने के लिए

  • एक एक विधि है कि अधिरोहित जा सकता है

को एक अज्ञात समारोह या

  • एक कॉल करने के लिए कॉल को शामिल कुछ भी कठिन है। आप भाग्यशाली हो सकते हैं, लेकिन आप इस पर भरोसा नहीं कर सकते हैं।

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

  • +4

    सी ++ में "अज्ञात फ़ंक्शन" या "ज्ञात फ़ंक्शन" नहीं हैं, उस पर आओ। –

    +0

    शायद संकलक यह जान सकता है कि एसटीएल स्ट्रिंग के लिए आकार() फ़ंक्शन का कोई प्रभाव नहीं पड़ता है क्योंकि कंपेलर एसटीएल के अपने कार्यान्वयन की पेशकश कर सकते हैं। – Kamchatka

    +0

    लेकिन std :: string std :: basic_string का एक विशेषज्ञता है, जो एक टेम्पलेट है, इसलिए इसमें पहले से ही परिभाषा उपलब्ध होगी। –

    3

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

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

    +0

    +1। –

    1

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

    आप एक लूप को बेहतर बनाने की कोशिश कर रहे घंटों को बर्बाद कर सकते हैं, केवल 0.001% प्रदर्शन वृद्धि प्राप्त करने के लिए। यदि आप प्रदर्शन के बारे में चिंतित हैं - प्रोफाइलर्स का उपयोग करें।

    +1

    आपको कोड को निराश नहीं करना चाहिए। आप नूथ को उद्धृत करने और ऑप्टिमाइज़ेशन टेक्नोलॉजी में अग्रिम करने के लिए घंटों को बर्बाद कर सकते हैं, केवल 0.000% प्रदर्शन वृद्धि प्राप्त करने के लिए। – peterchen

    +0

    मैं इस राय का तेजी से विचार कर रहा हूं कि "कभी भी सूक्ष्मदर्शीकरण" शिविर "स्वतंत्र रूप से माइक्रोप्रिमाइज़" के रूप में गलत नहीं है। आपको वास्तव में कभी नहीं कहना चाहिए। –

    +0

    @ जॉन डिबलिंग: मेरा कहना था कि आपको केवल "आंत महसूस" या कुछ द्वारा उपकरण (प्रोफाइलर्स) द्वारा प्रदान किए गए डेटा के आधार पर चीजों को अनुकूलित करना चाहिए। यदि आप बात करते हैं कि एक लूप धीमा होने जा रहा है, तो आपको यह मापना चाहिए कि वास्तव में कितना समय लगता है, और चीजों को संशोधित करके आपको कितना अतिरिक्त समय मिलता है। इसके अलावा, बड़ी तस्वीर देखने के लिए यह समझ में आता है। फ़ंक्शन में 200% प्रदर्शन वृद्धि में कोई बिंदु नहीं है जो कुल प्रोग्राम निष्पादन समय के 0.5% से कम लेता है। – SigTerm

    1

    रास्ते में वास्तव में कुछ भी गलत नहीं है (बी) यदि आप केवल कुछ लिखना चाहते हैं जो शायद (ए), और संभवतः तेज़ से भी बदतर नहीं होगा। यह यह भी स्पष्ट करता है कि आप जानते हैं कि स्ट्रिंग का आकार स्थिर रहेगा।

    संकलक size को स्थिर रख सकता है या नहीं भी; बस मामले में, आप स्वयं भी इस अनुकूलन को निष्पादित कर सकते हैं। मैं निश्चित रूप से ऐसा करूँगा अगर मुझे संदेह था कि जो कोड मैं लिख रहा था वह बहुत अधिक चल रहा था, भले ही मुझे यकीन नहीं था कि यह एक बड़ा सौदा होगा।यह करने के लिए बहुत सरल है, इसमें इसके बारे में सोचने में 10 से अधिक अतिरिक्त सेकंड नहीं लगते हैं, चीजों को धीमा करने की संभावना बहुत कम है, और, यदि कुछ और नहीं है, तो लगभग निश्चित रूप से अनियमित निर्माण को थोड़ा और जल्दी से चलाएगा।

    (इसके अलावा first शैली (ख) में चर अनावश्यक है,। Init अभिव्यक्ति के लिए कोड केवल एक बार चलाया जाता है)

    0

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

    std::size_t firststrlen = firststr.size(); 
    std::size_t secondstrlen = secondstr.size(); 
    for (std::size_t i = firststrlen; i < secondstrlen; i++){ 
         // ... 
    } 
    

    इसके अलावा, मैं कहना चाहिए कि आप का उपयोग करना चाहिए "std :: size_t" के बदले "अहस्ताक्षरित ", जैसा कि" std :: size_t "प्रकार एक प्लेटफ़ॉर्म से दूसरे में भिन्न हो सकता है, और" हस्ताक्षरित "का उपयोग करके प्लेटफॉर्म पर ट्रांक्शंस और त्रुटियों का कारण बन सकता है जिसके लिए" std :: size_t "प्रकार" unsigned long "है "हस्ताक्षरित int" का।

    1
    1. के रूप में करने का विरोध किया // do something कितना प्रतिशत समय की for में खर्च किया जाता है? (अनुमान न करें - इसका नमूना लें।) यदि यह < 10% है तो शायद आपके पास कहीं और समस्याएं हैं।

    2. हर कोई कहता है "इन दिनों कंपाइलर्स इतने स्मार्ट हैं।" वैसे वे गरीब कोडर से ज्यादा चालाक नहीं हैं जो उन्हें लिखते हैं। आपको भी स्मार्ट होने की आवश्यकता है। हो सकता है कि संकलक इसे अनुकूलित कर सके लेकिन यह क्यों न हो?

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

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