प्रदर्शन को बेहतर बनाने के लिए आप किन सरल तकनीकों का उपयोग करते हैं?


21

मैं उस तरीके के बारे में बात कर रहा हूं जिसमें हम आपके कोड को पढ़ने के लिए कठिन बनाने के बिना प्रदर्शन को बेहतर बनाने के लिए सरल दिनचर्या लिखते हैं ... उदाहरण के लिए, यह हमने सीखा के लिए विशिष्ट है:

for(int i = 0; i < collection.length(); i++ ){
   // stuff here
}

लेकिन, मैं आमतौर पर ऐसा तब करता हूं जब foreachयह लागू नहीं होता है:

for(int i = 0, j = collection.length(); i < j; i++ ){
   // stuff here
}

मुझे लगता है कि यह एक बेहतर तरीका है क्योंकि यह lengthकेवल एक बार विधि को बुलाएगा ... मेरी प्रेमिका का कहना है कि यह यद्यपि गुप्त है। क्या कोई अन्य सरल चाल है जो आप अपने स्वयं के विकास पर उपयोग करते हैं?


34
+1 केवल एक प्रेमिका रखने के लिए जो आपका कोड स्पष्ट नहीं होने पर आपको बताएगी।
क्रिस्टो सेप

76
आप हमें यह बताने के लिए पोस्ट कर रहे हैं कि आपकी कोई गर्लफ्रेंड है।
जोश के

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

5
@TomWij: सही (और पूर्ण) उद्धरण: "हमें छोटी क्षमताओं के बारे में भूलना चाहिए, समय के बारे में 97% कहना चाहिए: समय से पहले अनुकूलन सभी बुराई की जड़ है। फिर भी हमें उस महत्वपूर्ण 3% में अपने अवसरों को पारित नहीं करना चाहिए। "
रॉबर्ट हार्वे

3
@tomwij: यदि आप तीन प्रतिशत खर्च कर रहे हैं, तो परिभाषा के अनुसार आपको इसे समय-क्रिटिकल कोड में करना चाहिए, न कि अन्य 97% पर अपना समय बर्बाद करना चाहिए।
रॉबर्ट हार्वे

जवाबों:


28

समय से पहले की चर्चा को जड़ से ख़त्म कर देना

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

यह सामान्य सिद्धांतों की चर्चा नहीं है, लेकिन कोड में अनावश्यक अक्षमताओं को पेश करने से बचने के लिए कुछ बातों की जानकारी होना है।

अपने बड़े-ओ को जानो

यह शायद ऊपर लंबी चर्चा में विलय किया जाना चाहिए। यह बहुत सामान्य ज्ञान है कि एक लूप के अंदर एक लूप, जहां आंतरिक लूप एक गणना को दोहराता है, धीमा होने वाला है। उदाहरण के लिए:

for (i = 0; i < strlen(str); i++) {
    ...
}

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

जब एक मिलियन 32-बिट पूर्णांक को छाँटते हैं, तो बबल सॉर्ट जाने का गलत तरीका होगा । सामान्य तौर पर, सॉर्टिंग ओ (n * लॉग एन) समय (या बेहतर, मूलांक के अनुसार) के मामले में की जा सकती है, इसलिए जब तक आप नहीं जानते कि आपका डेटा छोटा होने जा रहा है, एक एल्गोरिथ्म देखें जो कम से कम O (n) है * लॉग एन)।

इसी तरह, डेटाबेस से निपटते समय, अनुक्रमणिकाओं के बारे में जागरूक रहें। यदि आप SELECT * FROM people WHERE age = 20, और आप लोगों (उम्र) पर कोई इंडेक्स नहीं रखते हैं, तो इसे बहुत तेज़ ओ (लॉग एन) इंडेक्स स्कैन के बजाय ओ (एन) अनुक्रमिक स्कैन की आवश्यकता होगी।

पूर्णांक अंकगणितीय पदानुक्रम

सी में प्रोग्रामिंग करते समय, ध्यान रखें कि कुछ अंकगणित संचालन दूसरों की तुलना में अधिक महंगे हैं। पूर्णांकों के लिए, पदानुक्रम कुछ इस तरह से होता है (कम से कम पहले महंगा):

  • + - ~ & | ^
  • << >>
  • *
  • /

यदि आप किसी मुख्यधारा के कंप्यूटर को लक्षित कर रहे हैं , तो कंपाइलर आमतौर पर चीजों n / 2को n >> 1अपने आप अनुकूलित कर लेगा , लेकिन यदि आप एक एम्बेडेड डिवाइस को लक्षित कर रहे हैं, तो आपको वह लक्जरी नहीं मिल सकती है।

इसके अलावा, % 2और & 1अलग शब्दार्थ है। विभाजन और मापांक आमतौर पर शून्य की ओर गोल होते हैं, लेकिन यह कार्यान्वयन को परिभाषित करता है। अच्छा राजभाषा ' >>और &हमेशा नकारात्मक अनंत की ओर गोल होता है, जो (मेरी राय में) बहुत अधिक समझ में आता है। उदाहरण के लिए, मेरे कंप्यूटर पर:

printf("%d\n", -1 % 2); // -1 (maybe)
printf("%d\n", -1 & 1); // 1

इसलिए, जो समझ में आता है उसका उपयोग करें। यह मत सोचिए कि % 2जब आप मूल रूप से लिखने जा रहे थे तब आप एक अच्छा लड़का हो & 1

महंगे फ्लोटिंग पॉइंट ऑपरेशन

भारी फ़्लोटिंग पॉइंट ऑपरेशन्स जैसे कि pow()और log()कोड से बचें जो वास्तव में उनकी आवश्यकता नहीं है, खासकर जब पूर्णांकों के साथ काम करना। उदाहरण के लिए, एक संख्या पढ़ना:

int parseInt(const char *str)
{
    const char *p;
    int         digits;
    int         number;
    int         position;

    // Count the number of digits
    for (p = str; isdigit(*p); p++)
        {}
    digits = p - str;

    // Sum the digits, multiplying them by their respective power of 10.
    number = 0;
    position = digits - 1;
    for (p = str; isdigit(*p); p++, position--)
        number += (*p - '0') * pow(10, position);

    return number;
}

न केवल यह pow()(और int<-> doubleइसका उपयोग करने के लिए आवश्यक रूपांतरणों) का उपयोग महंगा है, बल्कि यह सटीक नुकसान के लिए एक अवसर बनाता है (संयोग से, ऊपर दिए गए कोड में सटीक मुद्दे नहीं हैं)। इसीलिए जब मैं इस प्रकार के फंक्शन को गैर-गणितीय संदर्भ में इस्तेमाल करता हूं तो मैं विंस हो जाता हूं।

इसके अलावा, ध्यान दें कि नीचे "चतुर" एल्गोरिदम, जो प्रत्येक पुनरावृत्ति पर 10 से गुणा करता है, वास्तव में कोड की तुलना में अधिक संक्षिप्त है:

int parseInt(const char *str)
{
    const char *p;
    int         number;

    number = 0;
    for (p = str; isdigit(*p); p++) {
        number *= 10;
        number += *p - '0';
    }

    return number;
}

बहुत गहन उत्तर।
पैड्सस्लैकर

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

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

@ एंडी लेस्टर: वास्तव में, मेरा मतलब शुद्ध था। जीसीसी प्रलेखन में , यह बताता है कि कास्ट शुद्ध से थोड़ा सख्त है कि एक कास्ट फ़ंक्शन वैश्विक मेमोरी नहीं पढ़ सकता है। strlen()इसके सूचक तर्क द्वारा इंगित स्ट्रिंग की जांच करता है, जिसका अर्थ है कि यह संकुचित नहीं हो सकता है। इसके अलावा, strlen()वास्तव में glibc में शुद्ध के रूप में चिह्नित किया जाता हैstring.h
जॉय एडम्स

आप सही हैं, मेरी गलती है, और मुझे डबल-चेक करना चाहिए। मैं तोता परियोजना पर काम कर रहा हूँ pureया तो constदोनों के बीच सूक्ष्म अंतर के कारण या तो इसे हेडर फ़ाइल में डॉक्यूमेंट किया है। docs.parrot.org/parrot/1.3.0/html/docs/dev/c_functions.pod.html
एंडी लेस्टर

13

आपके प्रश्न और टिप्पणी के धागे से, यह आपको लगता है कि "लगता है" कि यह कोड परिवर्तन प्रदर्शन में सुधार करता है, लेकिन आप वास्तव में नहीं जानते कि यह करता है या नहीं।

मैं केंट बेक के दर्शन का प्रशंसक हूं :

"यह काम करो, इसे सही करो, इसे जल्दी करो।"

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

उदाहरण के लिए, .NET कोड के साथ गति का परीक्षण करने के लिए, मैं यह दावा करने के लिए NUnit के टाइमआउट विशेषता का उपयोग करता हूं कि किसी विशेष विधि के लिए कॉल एक निश्चित समय के भीतर निष्पादित होगी।

आपके द्वारा दिए गए कोड उदाहरण (और लूप के लिए पुनरावृत्तियों की एक बड़ी संख्या) के साथ NUnit के टाइमआउट विशेषता जैसी किसी चीज़ का उपयोग करके, आप वास्तव में साबित कर सकते हैं कि कोड के लिए आपके "सुधार" ने वास्तव में उस लूप के पूर्णता के साथ मदद की या नहीं।

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


2
जबकि मैं प्रोफाइलिंग में एक बड़ा विश्वास रखता हूं, मेरा मानना ​​है कि क्रिस्टियन को जिस तरह के सुझावों की तलाश है, उसे ध्यान में रखना स्मार्ट है। मैं हमेशा दो समान रूप से पठनीय विधियों का तेज चुनूंगा। मैच्योर ऑप्टिमाइज़ेशन में मजबूर होने का कोई मज़ा नहीं है।
एशेल्ली

यूनिट परीक्षणों के लिए जरूरी नहीं है, लेकिन यह हमेशा 20 मिनट खर्च करने के लिए यह जांचने के लिए सार्थक है कि क्या कुछ प्रदर्शन मिथक सच है या नहीं, खासकर क्योंकि उत्तर अक्सर संकलक और -O और -g ध्वज (या डीबग /) की स्थिति पर निर्भर करता है वीएस के मामले में रिलीज)।
mbq

+1 यह उत्तर प्रश्न से संबंधित मेरी टिप्पणी को पूरक बनाता है।
तमारा विजसमैन

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

@ निश्चित रूप से यदि आप दो समान रूप से पठनीय तरीकों के बारे में सोच सकते हैं और आप कम कुशल को चुनते हैं तो आप अपना काम नहीं कर रहे हैं? क्या वास्तव में कोई ऐसा करेगा?
ग्लेनट्रॉन

11

ध्यान रखें कि आपका संकलक अच्छी तरह से बदल सकता है:

for(int i = 0; i < collection.length(); i++ ){
   // stuff here
}

में:

int j = collection.length();
for(int i = 0; i < j; i++ ){
   // stuff here
}

या कुछ इसी तरह, अगर collectionलूप पर अपरिवर्तित है।

यदि यह कोड आपके आवेदन के समय के महत्वपूर्ण खंड में है, तो यह पता लगाने के लायक होगा कि यह मामला है या नहीं - या वास्तव में आप ऐसा करने के लिए संकलक विकल्प बदल सकते हैं या नहीं।

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

एक साइड नोट पर: यदि आप collectionतत्वों को जोड़कर या हटाकर लूप के अंदर बदलते हैं (हाँ, मुझे पता है कि यह एक बुरा विचार है, लेकिन ऐसा होता है) तो आपका दूसरा उदाहरण या तो सभी तत्वों पर लूप नहीं करेगा या अतीत तक पहुंचने की कोशिश करेगा सरणी का अंत।


1
केवल स्पष्ट रूप से क्यों नहीं?

3
यदि आप इसे स्पष्ट रूप से करते हैं, तो कुछ भाषाओं में, जो आपको जाँचती हैं, आप अपने कोड को कम कर देंगे। एक लूप के साथ संग्रह.लिफ्ट में कंपाइलर इसे आपके लिए बाहर ले जाता है और सीमा की जांच को छोड़ देता है। एक लूप के साथ अपने ऐप में कहीं और से कुछ स्थिर करने के लिए आपको हर पुनरावृत्ति पर सीमा की जांच करनी होगी। इसलिए यह मापना महत्वपूर्ण है - प्रदर्शन के बारे में अंतर्ज्ञान लगभग कभी सही नहीं होता है।
केट ग्रेगोरी

1
यही कारण है कि मैंने कहा "यह पता लगाने के लायक होगा"।
ChrisF

C # संकलक कैसे जान सकता है कि collection.length () संग्रह को संशोधित नहीं करता है, जिस तरह से stack.pop () करता है? मुझे लगता है कि यह संकलक के अनुकूलन के बजाय आईएल की जांच करना सबसे अच्छा होगा। C ++ में, आप एक विधि को const ('ऑब्जेक्ट नहीं बदलता है') के रूप में चिह्नित कर सकते हैं, इसलिए कंपाइलर इस अनुकूलन को सुरक्षित रूप से बना सकते हैं।
JBRWilkinson

1
@JBRW ऑप्टिमाइज़र जो ऐसा करते हैं, वे संग्रह के तरीकों के ओके-लेट-कॉल-कॉन्सटेंस-सम-हालांकि-हालांकि-इस-सी-सी + के बारे में भी जानते हैं। आखिरकार, आप केवल सीमा-जाँच कर सकते हैं यदि आप देख सकते हैं कि कोई चीज़ एक संग्रह है और यह जानती है कि इसकी लंबाई कैसे प्राप्त करें।
केट ग्रेगोरी

9

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


1
उसे प्रोग्रामिंग के बारे में एक किताब दें;)
जोएरी सेब्रचट्स

1
+1, क्योंकि हमारी अधिकांश गर्लफ्रेंड कोड स्पष्टता की तुलना में लेडी गागा में अधिक रुचि रखती हैं।
haploid

क्या आप बता सकते हैं कि इसकी सिफारिश क्यों नहीं की गई?
मैकनील

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

@ माचनील यदि आप उच्च स्तर की भाषा में काम कर रहे हैं, तो उसी स्तर पर सोचें।
स्पर्शकुंज

3

यह सामान्य प्रयोजन कोडिंग के लिए इतना लागू नहीं हो सकता है, लेकिन मैं इन दिनों ज्यादातर एम्बेडेड विकास करता हूं। हमारे पास एक विशिष्ट लक्ष्य प्रोसेसर है (जो तेजी से नहीं जा रहा है - यह 20-30 वर्षों में सिस्टम को रिटायर करने के समय तक काफी पुराना प्रतीत होगा), और कोड के बहुत समय के लिए बहुत ही प्रतिबंधात्मक समय सीमा। सभी प्रोसेसर की तरह, प्रोसेसर में कुछ क्वैर होते हैं, जिनके बारे में ऑपरेशन तेज या धीमे होते हैं।

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

एक विशिष्ट उदाहरण के रूप में, हमारे वर्तमान प्रोसेसर के लिए, 8 चक्रों के लिए प्रोसेसर को रोकते हुए, पाइपलाइन को शाखाएं खाली करती हैं। संकलक इस कोड लेता है:

 bool isReady = (value > TriggerLevel);

और इसे विधानसभा के बराबर में बदल देता है

isReady = 0
if (value > TriggerLevel)
{
  isReady = 1;
}

यह या तो 3 चक्र लेगा, या 10 से अधिक हो जाएगा isReady=1;। लेकिन प्रोसेसर के पास एक एकल-चक्र maxनिर्देश है, इसलिए इस अनुक्रम को उत्पन्न करने के लिए कोड लिखना बहुत बेहतर है, जो हमेशा 3 सेंटीमीटर लेने की गारंटी है:

diff = value-TriggerLevel;
diff = max(diff, 0);
isReady = min(1,diff);

जाहिर है, यहां इरादे मूल से कम स्पष्ट हैं। इसलिए हमने एक मैक्रो बनाया है, जिसका उपयोग हम तब करते हैं जब हम एक बूलियन ग्रेटर-थन तुलना चाहते हैं:

#define BOOL_GT(a,b) min(max((a)-(b),0),1)

//isReady = value > TriggerLevel;
isReady = BOOL_GT(value, TriggerLevel);

हम अन्य तुलनाओं के लिए समान चीजें कर सकते हैं। एक बाहरी व्यक्ति के लिए, कोड थोड़ा कम पठनीय होता है अगर हम केवल प्राकृतिक निर्माण का उपयोग करते हैं। हालांकि यह कोड के साथ काम करने में थोड़ा समय बिताने के बाद जल्दी स्पष्ट हो जाता है, और यह हर प्रोग्रामर को अपनी अनुकूलन तकनीकों के साथ प्रयोग करने से बेहतर है।


3

ठीक है, पहली सलाह इस तरह की समय से पहले की जाने वाली आशाओं से बचने की होगी जब तक कि आपको पता नहीं है कि कोड क्या हो रहा है, ताकि आप सुनिश्चित हों कि आप वास्तव में इसे तेजी से बना रहे हैं, और धीमा नहीं।

उदाहरण के लिए C # में कंपाइलर कोड को ऑप्टिमाइज़ करेगा यदि आप किसी ऐरे की लंबाई को कम कर रहे हैं, क्योंकि यह जानता है कि एरे को एक्सेस करने पर इंडेक्स को चेक करने की सीमा नहीं है। यदि आप सरणी की लंबाई को एक चर में रखकर इसे अनुकूलित करने का प्रयास करते हैं, तो आप लूप और सरणी के बीच कनेक्शन को तोड़ देंगे, और वास्तव में कोड को बहुत धीमा कर देंगे।

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


3

मेरे पास एक बहुत ही सरल तकनीक है।

  1. मैं अपना कोड काम करता हूं।
  2. मैं इसे गति के लिए परीक्षण करता हूं।
  3. यदि यह तेज़ है, तो मैं किसी अन्य सुविधा के लिए चरण 1 पर वापस जाता हूं। यदि यह धीमा है, तो मैं इसे टोंटी खोजने के लिए प्रोफ़ाइल करता हूं।
  4. मैं अड़चन ठीक करता हूं। चरण 1 पर वापस जाएं।

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


2

शॉर्ट-सर्किटिंग का लाभ उठाएं:

if(someVar || SomeMethod())

कोड के रूप में लंबे समय लेता है, और बस के रूप में पठनीय है:

if(someMethod() || someVar)

अभी तक यह समय के साथ और अधिक तेज़ी से मूल्यांकन करने वाला है।


1

छह महीने तक प्रतीक्षा करें, अपने बॉस को सभी नए कंप्यूटर खरीदने के लिए प्राप्त करें। गंभीरता से। प्रोग्रामर का समय दीर्घावधि में हार्डवेयर की तुलना में अधिक महंगा होता है। उच्च प्रदर्शन कंप्यूटर कोडर्स को गति के बारे में चिंतित हुए बिना सीधे तरीके से कोड लिखने की अनुमति देते हैं।


6
एर ... आपके ग्राहकों के प्रदर्शन के बारे में क्या? क्या आप अमीर हैं जो उनके लिए भी नए कंप्यूटर खरीद सकते हैं?
रॉबर्ट हार्वे

2
और हमने प्रदर्शन दीवार को लगभग मारा है; मल्टीकोर कम्प्यूटेशन ही एकमात्र तरीका है, लेकिन प्रतीक्षा करने से आपके प्रोग्राम इसका उपयोग नहीं करेंगे।
mbq

+1 यह उत्तर प्रश्न से संबंधित मेरी टिप्पणी को पूरक बनाता है।
तमारा विज्समैन

3
जब आपके पास हजारों या उपयोगकर्ताओं की संख्या होती है, तो कोई प्रोग्रामिंग समय हार्डवेयर से अधिक महंगा नहीं होता है। प्रोग्रामर का समय उपयोगकर्ता के समय से अधिक महत्वपूर्ण नहीं है, इसे जितनी जल्दी हो सके अपने सिर के माध्यम से प्राप्त करें।
HLGEM

1
अच्छी आदतों में उतरें, फिर यह कोई प्रोग्रामर समय नहीं लेता है क्योंकि यह वही है जो आप हर समय करते हैं।
डोमिनिक मैकडोनेल

1

समय से पहले बहुत अधिक अनुकूलन न करने का प्रयास करें, फिर जब आप अनुकूलन करते हैं तो पठनीयता के बारे में थोड़ी कम चिंता करें।

वहाँ बहुत कम मुझे अनावश्यक जटिलता से अधिक नफरत है, लेकिन जब आप एक जटिल स्थिति से टकराते हैं तो एक जटिल समाधान की आवश्यकता होती है।

यदि आप कोड को सबसे स्पष्ट तरीके से लिखते हैं, तो यह बताते हुए एक टिप्पणी करें कि जटिल परिवर्तन करने पर इसे क्यों बदल दिया गया है।

विशेष रूप से आपके अर्थ के बावजूद, मुझे लगता है कि डिफ़ॉल्ट दृष्टिकोण के विपरीत बूलियन करने में बहुत बार कभी-कभी मदद मिलती है:

for(int i = 0, j = collection.length(); i < j; i++ ){
// stuff here
}

बन सकता है

for(int i = collection.length(); i > 0; i-=1 ){
// stuff here
}

कई भाषाओं में जब तक आप "सामान" भाग के लिए उपयुक्त समायोजन करते हैं और यह अभी भी पठनीय है। यह सिर्फ उस समस्या को नहीं बताता है जिस तरह से ज्यादातर लोग इसे करने के बारे में सोचते हैं क्योंकि यह पीछे की ओर गिना जाता है।

उदाहरण के लिए सी # में:

        string[] collection = {"a","b"};

        string result = "";

        for (int i = 0, j = collection.Count() - 1; i < j; i++)
        {
            result += collection[i] + "~";
        }

के रूप में भी लिखा जा सकता है:

        for (int i = collection.Count() - 1; i > 0; i -= 1)
        {
            result = collection[i] + "~" + result;
        }

(और हाँ, आपको एक जुड़ाव या एक स्ट्रिंगर के साथ ओ करना चाहिए, लेकिन मैं एक सरल उदाहरण बनाने की कोशिश कर रहा हूं)

कई अन्य तरकीबें हैं, जिनका उपयोग करना मुश्किल है, लेकिन उनमें से कई सभी भाषाओं पर लागू नहीं होती हैं, जैसे कि स्ट्रिंग रीअसाइनमेंट जुर्माना या बाइनरी मोड में पाठ फ़ाइलों को पढ़ने से बचने के लिए पुरानी vb में असाइनमेंट के बाईं ओर मध्य का उपयोग करना। जब फ़ाइल रीडआउट के लिए फ़ाइल बहुत बड़ी हो, तो .net बफ़रिंग पेनल्टी प्राप्त करने के लिए।

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


यह एक समाधान है, लेकिन संकलक संभावित रूप से अधिकांश आम वर्गों की लंबाई के लिए चेतावनी के रूप में थूक देगा () एक अहस्ताक्षरित प्रकार देता है
stijn

लेकिन सूचकांक को उलटने से, पुनरावृति स्वयं अधिक जटिल हो सकती है।
तमारा विज्समैन

@stijn मैं c # के बारे में सोच रहा था जब मैंने इसे लिखा था, लेकिन शायद यह सुझाव उस कारण के लिए भाषा विशिष्ट श्रेणी में भी आता है - संपादित देखें ... @ToWij निश्चित रूप से, मुझे नहीं लगता कि इस प्रकृति के किसी भी सुझाव पर कई हैं उस के जोखिम को न चलाएं। यदि आपका // सामान किसी प्रकार का स्टैक हेरफेर था, तो हो सकता है कि तर्क को सही तरीके से उलट देना भी संभव न हो, लेकिन कई मामलों में यह बहुत ही भ्रामक होता है और उन मामलों में से ज्यादातर IMHO में सावधानीपूर्वक किए जाने पर भी भ्रमित नहीं होते।
बिल

आप सही हे; C ++ में मैं अभी भी 'सामान्य' लूप को पसंद करूंगा, लेकिन पुनरावृत्ति से बाहर की गई लंबाई () कॉल के साथ (जैसे कि const size_t len ​​= collection.length ();) के लिए (size_t i = 0; i <len; ++ i) {}) दो कारणों से: मुझे लगता है कि 'सामान्य' फॉरवर्ड काउंटिंग लूप अधिक पठनीय / समझने योग्य है (लेकिन यह शायद सिर्फ इसलिए कि यह अधिक सामान्य है), और यह लूप इनवेरिएंट लेंथ () लूप से बाहर ले जाता है।
टिजिन

1
  1. प्रोफाइल। क्या हमें भी कोई समस्या है? कहा पे?
  2. 90% मामलों में जहां यह किसी तरह से IO संबंधित है, कैशिंग लागू करें (और शायद अधिक मेमोरी प्राप्त करें)
  3. यदि यह CPU से संबंधित है, तो कैशिंग लागू करें
  4. यदि प्रदर्शन अभी भी एक समस्या है, तो हमने सरल तकनीकों के दायरे को छोड़ दिया है - गणित करते हैं।

1

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


1

मेरे लिए सबसे सरल एक स्टैक का उपयोग तब संभव है जब भी एक सामान्य मामला उपयोग पैटर्न की एक सीमा फिट होती है, कहते हैं, [0, 64), लेकिन दुर्लभ मामले हैं जिनके पास कोई ऊपरी ऊपरी सीमा नहीं है।

सरल सी उदाहरण (पहले):

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    int* values = calloc(n, sizeof(int));

    // do stuff with values
    ...
    free(values);
}

और बाद में:

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    int values_mem[64] = {0}
    int* values = (n <= 64) ? values_mem: calloc(n, sizeof(int));

    // do stuff with values
    ...
    if (values != values_mem)
        free(values);
}

मैंने इसे इस तरह से सामान्यीकृत किया है, क्योंकि इस प्रकार के हॉटस्पॉट्स की रूपरेखा में बहुत अधिक फसल होती है:

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    MemFast values_mem;
    int* values = mf_calloc(&values_mem, n, sizeof(int));

    // do stuff with values
    ...

    mf_free(&values_mem);
}

जब डेटा आवंटित किया जा रहा है, तो 99.9% मामलों में उपर्युक्त छोटे स्टैक का उपयोग करता है, और अन्यथा ढेर का उपयोग करता है।

C ++ में मैंने इसे एक मानक-अनुरूप छोटे अनुक्रम ( SmallVectorवहाँ बाहर कार्यान्वयन के समान ) के साथ सामान्यीकृत किया है जो एक ही अवधारणा के चारों ओर घूमता है।

यह एक महाकाव्य अनुकूलन नहीं है (मैंने 1.8 सेकंड से नीचे के ऑपरेशन को पूरा करने के लिए 3 सेकंड के लिए, कह दिया है), लेकिन इसे लागू करने के लिए ऐसे तुच्छ प्रयास की आवश्यकता है। जब आप कोड की एक पंक्ति शुरू करने और दो को बदलने के द्वारा 3 सेकंड से 1.8 सेकंड तक कुछ नीचे प्राप्त कर सकते हैं, तो यह इस तरह के एक छोटे से हिरन के लिए एक बहुत अच्छा धमाका है।


0

वैसे प्रदर्शन परिवर्तनों की एक बहुत कुछ है जो आप डेटा तक पहुँचने के दौरान कर सकते हैं जो आपके आवेदन पर बहुत अधिक प्रभाव डालेगा। यदि आप डेटाबेस तक पहुंचने के लिए क्वेरी लिखते हैं या ORM का उपयोग करते हैं, तो आपको अपने द्वारा उपयोग किए जाने वाले डेटाबेस के लिए कुछ प्रदर्शन ट्यूनिंग पुस्तकें पढ़ने की आवश्यकता है। संभावना है कि आप खराब प्रदर्शन करने वाले टेचीनीक्स का उपयोग कर रहे हैं। अज्ञान के सिवाय ऐसा करने का कोई कारण नहीं है। यह समय से पहले का अनुकूलन नहीं है (मैं उस आदमी को श्राप देता हूं जिसने यह कहा था क्योंकि यह इतना व्यापक रूप से गूढ़ हो चुका है जितना प्रदर्शन की चिंता कभी नहीं की जाती), यह अच्छा डिजाइन है।

SQL सर्वर के लिए प्रदर्शन एन्हांसर का सिर्फ एक त्वरित नमूना: उचित अनुक्रमित का उपयोग करें, कर्सर से बचें - सेट-आधारित तर्क का उपयोग करें, जहाँ संभव हो, वहाँ का उपयोग करें, जहां विचारों के शीर्ष पर ढेर न हों, ज़रूरत से ज़्यादा डेटा न लौटाएँ या अधिक आपकी आवश्यकता से अधिक स्तंभ, सहसंबद्ध उपश्रेणियों का उपयोग नहीं करते हैं।


0

यदि यह C ++ है, तो आपको इसके ++iबजाय आदत में शामिल होना चाहिए i++++iयह कभी भी बदतर नहीं होगा, इसका मतलब बिल्कुल स्टैंड-अलोन स्टेटमेंट के समान है, और कुछ मामलों में यह प्रदर्शन में सुधार हो सकता है।

यह ऑफ-कोड पर मौजूदा कोड को बदलने के लायक नहीं है जो इसे मदद करेगा, लेकिन इसमें प्रवेश करना एक अच्छी आदत है।


0

मैं इस पर थोड़ा अलग हो गया हूं। बस आपको यहाँ मिलने वाली सलाह के बाद ज्यादा फर्क नहीं पड़ने वाला है, क्योंकि कुछ गलतियाँ हैं जिन्हें आपको करने की ज़रूरत है, जिन्हें आपको ठीक करने की ज़रूरत है, जो आपको तब सीखने की ज़रूरत है।

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

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

आप कोड में बड़े बदलाव के बिना इन समस्याओं को कुछ हद तक ठीक कर सकते हैं।

तब यदि आप भाग्यशाली हैं तो आप सीख सकते हैं कि कम डेटा संरचना बेहतर है, और यह कि अस्थायी असंगतता को सहन करने में सक्षम होने से बेहतर है कि संदेशों की लहरों के साथ कई चीजों को कसकर रखने की कोशिश करें।

आप लूप कैसे लिखते हैं इसका वास्तव में कोई लेना देना नहीं है।

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