2010-03-01 13 views
6

पटकथा भाषाओं में PHP जैसे के लिए इस तरह पाश के लिए एक होने में precalculated limiters का उपयोग कर एक बहुत बुरा विचार होगा।सी ++ छोरों

यदि यह सी ++ उदाहरण के लिए एक समान PHP स्क्रिप्ट के लिए अनुवाद किया गया था स्ट्रिंग की लंबाई होगा (लोगों का मानना ​​है कि जैसे वे मुझे बताने की क्यों कोड < के इस टुकड़े इसके बारे में यहाँ बुरी बात डालने> है के लिए) प्रत्येक पाश चक्र की गणना की। इससे यथार्थवादी स्क्रिप्ट में भारी मात्रा में नुकसान होगा।

मैंने सोचा कि यह सी ++ कार्यक्रमों पर लागू होगा, लेकिन जब मैं ट्यूटोरियल्स को देखता हूं, कई ओपन-सोर्स लाइब्रेरीज़ और कोड के अन्य टुकड़े मुझे लगता है कि लूप के लिए लिमिटर को सटीक नहीं किया गया है।

  • क्या मुझे स्ट्रिंग s की लंबाई को सटीक करना चाहिए?
  • लिमिटर हमेशा सटीक क्यों नहीं है? (इसे ट्यूटोरियल और उदाहरणों में देखा गया)
  • क्या कंपाइलर द्वारा कुछ अनुकूलन किया गया है?
+0

ट्यूटोरियल आमतौर पर गति के बजाय पठनीयता के लिए लिखे जाते हैं। उदाहरण में स्पष्ट, धीमे कोड लिखना गलत नहीं है। –

उत्तर

11

यह सब रिश्तेदार है।

पीएचपी व्याख्या की है, लेकिन अगर s.length बूँदें PHP दुभाषिया के संकलित भाग में, यह धीमा नहीं होगा। लेकिन यदि यह धीमा है, तो s[i] में बिताए गए समय के बारे में क्या, और cout << में बिताए गए समय के बारे में क्या?

अन्य सामानों के साथ घूमते समय लूप ओवरहेड पर ध्यान केंद्रित करना वास्तव में आसान है।

जैसा कि आपने इसे सी ++ में लिखा है, और cout कंसोल पर लिख रहे थे, क्या आप जानते हैं कि क्या हावी होगा? cout, दूर और दूर, क्योंकि वह निर्दोष दिखने वाला << ऑपरेटर लाइब्रेरी कोड और सिस्टम रूटीन का एक विशाल ढेर का आह्वान करता है।

+0

+1 सही उत्तर! –

2

अनुकूलक वास्तव में length दूर अगर वह निर्धारित करने के लिए कि अपने मूल्य में परिवर्तन नहीं होगा सक्षम है करने के लिए कॉल अनुकूलन करने के लिए सक्षम हो सकता है - फिर भी, आप सुरक्षित पक्ष अगर आप इसे precalculate पर हैं (कई मामलों में, हालांकि, ऑप्टिमाइज़ेशन संभव नहीं होगा क्योंकि यह कंपाइलर को स्पष्ट नहीं है कि लूप के दौरान स्थिति चर संभव हो सकता है या नहीं)।

कई मामलों में, इससे कोई फर्क नहीं पड़ता क्योंकि प्रश्न में लूप प्रदर्शन-प्रासंगिक नहीं है। क्लासिक for(int i=0; i < somewhat(); ++i) का उपयोग for(int i=0,end=somewhat(); i < end; ++i से पढ़ने और पढ़ने के लिए दोनों कम काम है।

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

1
  1. शायद।
  2. पठनीयता के लिए।
  3. कभी-कभी। यह इस बात पर निर्भर करता है कि लूप के अंदर लंबाई नहीं बदलेगी यह पता लगाने में कितना अच्छा लगा।
0

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

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

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

कोड लिखते समय पठनीयता भी बहुत महत्वपूर्ण है!
अनुकूलन बहुत सावधानी से किया जाना चाहिए और गहन प्रोफाइलिंग के बाद ही!

1

आप सही हैं, s.length() आमतौर पर प्रत्येक लूप पुनरावृत्ति पर मूल्यांकन किया जाएगा। आप लिखने से बेहतर हैं:

size_t len = s.length(); 
for (size_t i = 0; i < len; ++i) { 
    ... 
} 

उपर्युक्त के बजाय। उस ने कहा, केवल कुछ ही पुनरावृत्तियों के साथ एक लूप के लिए, यह वास्तव में कोई फर्क नहीं पड़ता कि कितनी बार कॉल लंबाई() किया जाएगा।

+3

नोट: केवल यह इस तरह से करें यदि आप जानते हैं * लंबाई बदल नहीं सकती है। –

+2

उम, क्या आप 'std :: string' के बारे में बात कर रहे हैं? क्योंकि मुझे पूरा यकीन है कि 'std :: string' लंबाई को हर बार पुन: गणना करने के बजाय स्ट्रिंग की एक संपत्ति के रूप में रखता है। –

+0

@mmyers: हाँ, यह एक "संपत्ति" है, लेकिन यह अभी भी एक फ़ंक्शन कॉल है। कंपाइलर फ़ंक्शन कॉल को इनलाइन करने के लिए पर्याप्त स्मार्ट हो सकता है, ऐसा नहीं हो सकता है। कंपाइलर या तो कार्रवाई कर सकता है और अभी भी मानक के अनुरूप है। –

0

std::string.length() निश्चित चर लौटाता है, जो कंटेनर में स्टोर करता है। यह पहले से ही

+3

हां, लेकिन कंपाइलर को फ़ंक्शन कॉल को इनलाइन करने के लिए पर्याप्त स्मार्ट होना जरूरी नहीं है। –

+0

आवश्यक रूप से पूर्व निर्धारित नहीं है: यह मानक द्वारा अनिवार्य नहीं है। लेकिन यह ** ** मामला होने की संभावना है। Http://stackoverflow.com/questions/256033/is-stdstring-size-a-o1-operation –

+0

उन प्रविष्टियों को चिह्नित किया गया है '' (नोट ए) '' में निरंतर जटिलता होनी चाहिए। – zabulus

0

precalculated है आप स्ट्रिंग की लंबाई precalculate सकता है केवल यदि आप जानते स्ट्रिंग कभी पाश अंदर परिवर्तन नहीं होगा।

मुझे नहीं पता कि यह ट्यूटोरियल्स में ऐसा क्यों किया जाता है। कुछ अनुमान:
1) आपको आदत में लाने के लिए ताकि आप लूप के अंदर स्ट्रिंग के मान को बदलते समय न हो जाएं।
2) क्योंकि यह समझना आसान है।

हाँ, अनुकूलक इस सुधार करने के लिए, अगर यह निर्धारित कर सकते हैं स्ट्रिंग

+0

डाउनवोट क्यों? –

+1

समयपूर्व अनुकूलन सभी बुराइयों की जड़ है।/डी Knuth। (मेरा डाउनवोट नहीं, बीटीडब्ल्यू, हालांकि मैं भावना के साथ symphatize कर सकते हैं।) –

+0

हाँ, मैं उस उद्धरण से सहमत हूं। मैंने थोड़ा और स्पष्ट होने के लिए मेरा जवाब दोहराया। –

3

यह string कैसे कार्यान्वित किया जाता है पर निर्भर करता है में परिवर्तन नहीं होगा की कोशिश करेंगे।

शून्य समाप्त तारों पर आपको प्रत्येक पुनरावृत्ति पर आकार की गणना करना होगा।

std::string एक कंटेनर और कार्यान्वयन पर आकार हे (1) समय में वापस आ जाना चाहिए,
यह निर्भर करता है (फिर) है।

+0

ओ (1) - गारंटी नहीं है: http://stackoverflow.com/questions/256033/is-stdstring-size-a-o1-operation –

+0

@Pontus Gagge, सुधार के लिए धन्यवाद। –

0

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

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

यह सटीक है लेकिन अक्सर आवश्यक नहीं है।

0

इस विशेष मामले में, std::string.length()आमतौर पर (लेकिन necessarily नहीं) निरंतर समय के संचालन और आमतौर पर बहुत ही कुशल है।

सामान्य मामले के लिए, लूप समाप्ति स्थिति किसी भी अभिव्यक्ति हो सकती है, न केवल लूप इंडेक्स चर की तुलना (वास्तव में, सी/सी ++ किसी विशेष इंडेक्स को पहचान नहीं पाती है, केवल एक प्रारंभिक अभिव्यक्ति, एक लूप परीक्षण अभिव्यक्ति और एक पाश काउंटर अभिव्यक्ति (जो सिर्फ के माध्यम से हर बार निष्पादित किया जाता है)। C/C++ पाश के लिए मूल रूप से एक do/while यौगिक बयान के लिए वाक्यात्मक चीनी है।

0

std::sting::length() एक सटीक मूल्य देता है। अन्य STL कंटेनर एक precalculated मूल्य

यह कैसे आंतरिक भंडारण पर निर्भर करता है रिटर्न हर बार जब आप विधि size() जैसे

  • std::list::size() आकार और
  • std::vector::size() पुनर्गणना फोन उनके आकार पुनर्गणना कंटेनर लागू किया गया है। std::vector क्षमता 2^n और std::list के साथ एक सरणी है एक लिंक्ड सूची है।

4

आपको सरल कोड को उचित ठहराना सीखना चाहिए। अपने आप को यह समझाने की कोशिश करें कि जितनी जल्दी या बाद में आप स्ट्रिंग :: लंबाई कार्यान्वयन को अधिक अनुकूलित करने के लिए प्रतिस्थापित करेंगे। (भले ही आपकी परियोजना की सभी समय सीमाएं याद आती हैं, और स्ट्रिंग :: लंबाई को अनुकूलित करने से आपकी समस्याएं कम से कम होंगी।) इस तरह की सोच आपको उन चीजों पर ध्यान केंद्रित करने में मदद करेगी, जो वास्तव में महत्वपूर्ण हैं, भले ही यह हमेशा आसान न हो ...

0

बस जानकारी के लिए, मेरे कंप्यूटर पर, जी ++ 4.4.2, कोड के दिए गए टुकड़े के साथ -O3, फ़ंक्शन std::string::length() const को 8 बार कहा जाता है।

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

0

यदि आपका प्रोग्राम स्ट्रिंग्स (memcpy के साथ) की प्रतिलिपि बनाने जैसे हर समय तारों पर बहुत से संचालन करता है तो स्ट्रिंग की लंबाई को कैश करने के लिए यह समझ में आता है।

ओपनसोर्स कोड में मैंने देखा है इसका एक अच्छा उदाहरण redis है।

sds.h में (सरल गतिशील स्ट्रिंग्स) sdshdr संरचना को देखो:

struct sdshdr { 
    long len; 
    long free; 
    char buf[]; 
}; 

आप देख सकते हैं यह लंबाई (में लेन क्षेत्र) और भी मुक्त अंतरिक्ष buf चरित्र सरणी का कैश शून्य चरित्र के बाद उपलब्ध (मुफ्त फ़ील्ड में)।

तो कुल स्मृति buf के लिए आवंटित

len + free 

इस मामले buf संशोधित करने की आवश्यकता में एक realloc बचत होती है और यह पहले से ही उपलब्ध अंतरिक्ष में फिट बैठता है।

2

मुझे php के बारे में पता नहीं है लेकिन मैं बता सकता हूं कि c++ क्या करता है। पर विचार करें :

std::string s("Rajendra"); 
for (unsigned int i = 0; i < s.length(); i++) 
{ 
    std::cout << s[i] << std::endl; 
} 

आप length() की परिभाषा को देख के लिए जाते हैं (सही length() पर क्लिक करें और "परिभाषा पर जाएँ" पर क्लिक करें) या यदि आप दृश्य का उपयोग कर रहे असिस्ट एक्स तो length() पर कर्सर रखकर और Alt+G प्रेस , तो आपको निम्न मिलेगा:

size_type __CLR_OR_THIS_CALL length() const 
    { // return length of sequence 
    return (_Mysize); 
    } 

कहाँ _Mysize प्रकार int, जो स्पष्ट रूप स्ट्रिंग की कि लंबाई का पता चलता है की है पूर्व गणना की है और केवल संग्रहीत मूल्यकी प्रत्येक कॉल लौटे किया जा रहा है।

हालांकि, आईएमपीओ (मेरी व्यक्तिगत राय में), यह कोडिंग शैली खराब है और इसे सबसे अच्छी तरह से बचा जाना चाहिए। मैं निम्नलिखित पसंद करेंगे:

std::string s("Rajendra"); 
int len = s.length(); 
for (unsigned int i = 0; i < len; i++) 
{ 
    std::cout << s[i] << std::endl; 
} 

इस तरह, आप length() समारोह समय की स्ट्रिंग संख्या है, जो धक्का बचाता की लंबाई के बराबर बुला और ढेर फ्रेम के पॉपिंग के ऊपरी बचत होगी। आपकी स्ट्रिंग बड़ी होने पर यह बहुत महंगा हो सकता है।
उम्मीद है कि मदद करता है।

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