2009-01-21 8 views
40

वहाँक्या सी # में ++ i और i ++ के बीच कोई प्रदर्शन अंतर है?

for(int i = 0; i < 10; i++) { ... } 

और

for(int i = 0; i < 10; ++i) { ... } 

की तरह कुछ का उपयोग कर के बीच किसी भी प्रदर्शन अंतर है या संकलक इस तरह से कि वे समान रूप से तेजी से मामले में जहां वे कार्यात्मक रूप से बराबर कर रहे हैं में अनुकूलन करने के लिए सक्षम है ?

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

+1

यह बंद नहीं होना चाहिए था। लेकिन वैसे भी, यदि आप इसे संकलित करते हैं और MSIL को देखने के लिए ildasm.exe का उपयोग करते हैं, तो आप देखेंगे कि दो उदाहरण समान एमएसआईएल के परिणामस्वरूप हैं। –

+0

फिर से खोलने के लिए वोट दिया गया। जॉन शीहान, tvanfosson, ctacke, मार्क ग्रेवल .. यदि आप बंद करने के लिए मतदान कर रहे हैं .. प्रश्न में डुप्लिकेट संपादित करें और प्रदान करें! मुझे डुप्ली – mmcdole

+0

पर कोई लिंक नहीं दिख रहा है डुप्लिकेट के साथ एक जवाब था, मुझे नहीं पता कि यह कहां गया था। –

उत्तर

34

के लिए ++ मैं और मैं इस मामले में ++ उत्पन्न मध्यवर्ती कोड में कोई अंतर नहीं है। दोनों छोरों के लिए

class Program 
{ 
    const int counter = 1024 * 1024; 
    static void Main(string[] args) 
    { 
     for (int i = 0; i < counter; ++i) 
     { 
      Console.WriteLine(i); 
     } 

     for (int i = 0; i < counter; i++) 
     { 
      Console.WriteLine(i); 
     } 
    } 
} 

उत्पन्न आईएल कोड एक ही है: इस कार्यक्रम को देखते हुए

IL_0000: ldc.i4.0 
    IL_0001: stloc.0 
    // Start of first loop 
    IL_0002: ldc.i4.0 
    IL_0003: stloc.0 
    IL_0004: br.s  IL_0010 
    IL_0006: ldloc.0 
    IL_0007: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_000c: ldloc.0 
    IL_000d: ldc.i4.1 
    IL_000e: add 
    IL_000f: stloc.0 
    IL_0010: ldloc.0 
    IL_0011: ldc.i4  0x100000 
    IL_0016: blt.s  IL_0006 
    // Start of second loop 
    IL_0018: ldc.i4.0 
    IL_0019: stloc.0 
    IL_001a: br.s  IL_0026 
    IL_001c: ldloc.0 
    IL_001d: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_0022: ldloc.0 
    IL_0023: ldc.i4.1 
    IL_0024: add 
    IL_0025: stloc.0 
    IL_0026: ldloc.0 
    IL_0027: ldc.i4  0x100000 
    IL_002c: blt.s  IL_001c 
    IL_002e: ret 

जिसके अनुसार, यह संभव है (अत्यधिक संभावना नहीं है, हालांकि) कि JIT कम्पाइलर कुछ संदर्भों में कुछ अनुकूलन कर सकते हैं जो दूसरे संस्करण पर एक संस्करण का पक्ष लेगा। यदि ऐसा अनुकूलन है, हालांकि, यह केवल लूप के अंतिम (या शायद पहले) पुनरावृत्ति को प्रभावित करेगा।

संक्षेप में, वहाँ सरल पूर्व वेतन वृद्धि या पाशन निर्माण में नियंत्रण चर है कि आप का वर्णन किया है के बाद वेतन वृद्धि की क्रम में कोई अंतर नहीं किया जाएगा।

+0

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

0

this answer के अनुसार, i ++ ++ i से अधिक एक CPU निर्देश का उपयोग करता है। लेकिन क्या यह एक प्रदर्शन अंतर में परिणाम है, मुझे नहीं पता।

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

4

दोस्तों, दोस्तों, "उत्तर" सी और सी ++ के लिए हैं।

सी # एक अलग जानवर है।

आईएसएलएएसएम का उपयोग संकलित आउटपुट को देखने के लिए करें ताकि यह पता चल सके कि कोई एमएसआईएल अंतर है या नहीं।

7

आह ... फिर से खोलें। ठीक। यहाँ सौदा है।

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

यहां आप क्या करना चाहते हैं।

आप जो देखने की कोशिश कर रहे हैं उसके कुछ नमूने लें। जाहिर है कि यदि आप चाहें तो आप दीवार घड़ी का समय निकाल सकते हैं - लेकिन मुझे लगता है कि आप उससे अधिक जानना चाहते हैं।

यहां स्पष्ट नहीं है। सी # कंपाइलर कुछ एमएसआईएल अनुक्रम उत्पन्न करता है जो कई स्थितियों में गैर-इष्टतम हैं। जेआईटी ने इन भाषाओं और अन्य भाषाओं से quirks से निपटने के लिए ट्यून किया। समस्या: केवल 'quirks' किसी ने देखा है देखा गया है।

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

आप डीबगर के तहत कोड शुरू नहीं करना चाहते हैं या जेआईटी गैर-अनुकूलित कोड उत्पन्न करेगा - और ऐसा लगता है जैसे आप जानना चाहते हैं कि यह वास्तविक वातावरण में कैसे व्यवहार करेगा। जेआईटी डीबग जानकारी को अधिकतम करने और वर्तमान स्रोत स्थान को 'कूदने' से कम करने के लिए करता है। डीबगर के तहत कभी भी एक perf मूल्यांकन शुरू नहीं करें।

ठीक है। तो एक बार कोड एक बार चलाया जाता है (यानी: जेआईटी ने इसके लिए कोड उत्पन्न किया है), फिर नींद के दौरान डीबगर संलग्न करें (या जो भी हो)। फिर दो दिनचर्या के लिए उत्पन्न x86/x64 देखें।

मेरा आंत मुझे बताता है कि यदि आप वर्णित ++ i/i ++ का उपयोग कर रहे हैं - यानी: स्टैंड स्टैंड अकेले अभिव्यक्ति में जहां रावल्यू परिणाम का पुन: उपयोग नहीं किया जाता है - इसमें कोई अंतर नहीं होगा। लेकिन यह पता लगाने और सभी साफ सामान देखने के लिए मजेदार नहीं होगा! :)

+0

यह बहुत जानकारीपूर्ण है । धन्यवाद! –

3

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

0
static void Main(string[] args) { 
    var sw = new Stopwatch(); sw.Start(); 
    for (int i = 0; i < 2000000000; ++i) { } 
    //int i = 0; 
    //while (i < 2000000000){++i;} 
    Console.WriteLine(sw.ElapsedMilliseconds); 

3 रन से औसत: के लिए
साथ मैं ++: 1307 के लिए ++ के साथ मैं: 1314

जबकि साथ मैं ++: 1261 ++ के साथ मैं, जबकि: एक 1276

है कि 2,53 गीगा पर सेलेरॉन डी। प्रत्येक पुनरावृत्ति में लगभग 1.6 सीपीयू चक्र होते थे। इसका मतलब है कि सीपीयू प्रत्येक चक्र से 1 से अधिक निर्देश निष्पादित कर रहा था या जेआईटी कंपाइलर ने लूप को अनलॉक किया था। I ++ और ++ के बीच का अंतर केवल प्रति 0.01 CPU चक्र प्रति पुनरावृत्ति था, संभवतः पृष्ठभूमि में ओएस सेवाओं के कारण होता था।

+1

देखें कि डेवी लैंडमैन यहां अपना कोड कैसे दिखाता है (दूसरे कोड ब्लॉक में): http://stackoverflow.com/questions/419952/could-you-please-review-my-quick-int-parser-implementation#421693 प्रक्रिया प्राथमिकता, एफ़िनिटी और थ्रेड प्राथमिकता सेट करके, आप अधिक सटीक माप प्राप्त कर सकते हैं। –

2

आप इस प्रश्न पूछ रहे हैं, तो आप गलत समस्या को हल करने की कोशिश कर रहे हैं।

पहले सवाल पूछने के लिए "मैं इसे कैसे तेजी से चलाने बनाकर मेरे सॉफ्टवेयर के साथ ग्राहकों की संतुष्टि में सुधार करने के?" है और जवाब लगभग कभी भी "मैं ++ के बजाय ++ का उपयोग नहीं करता" या इसके विपरीत।

डरावना पद "Hardware is Cheap, Programmers are Expensive" कोडिंग से:
नियम 1::

अनुकूलन की

नियम ऐसा मत करो।
नियम 2 (केवल विशेषज्ञों के लिए): अभी तक ऐसा न करें।
- M.A. Jackson

मैं नियम 2 पढ़ें "पहले लिखने स्वच्छ, साफ कोड है कि अपने ग्राहकों की जरूरतों को पूरा करती है, तो यह इसकी गति बढ़ाने जहां यह बहुत धीमी गति से है" मतलब करने के लिए। यह अत्यधिक संभावना नहीं है कि ++i बनाम i++ समाधान होने जा रहा है है।

+1

कमाल, है ना? यहां सबसे अच्छी प्रतिक्रिया - और केवल एक आवश्यक है। –

+3

प्रश्न "कौन सा तेज है" मेरे साथ कभी नहीं हुआ। मैं हमेशा '++ i' का उपयोग करता हूं। क्यूं कर? क्योंकि मैंने * बाएं से दाएं * को पढ़ा है और '++ i' को" i' के मान में वृद्धि "के रूप में पढ़ा गया है और नहीं" मैं '' लेता हूं और इसके मूल्य में वृद्धि करता हूं "। चूंकि '++' बाईं तरफ है, मैं तुरंत देख सकता हूं कि क्या हो रहा है, मुझे अपनी आंखों को दाईं ओर ले जाने की आवश्यकता नहीं है :) यदि आपके पास एक लंबा चर नाम है, तो '++ कुछ' अधिक पठनीय है । – Jabba

+3

-1: वास्तविक प्रश्न को अनदेखा करते समय ओपी ने कभी भी एक प्रश्न का उत्तर नहीं दिया। ओपी को ट्रोल भी कहा जाता है। – JMD

3

जिम Mischel has shown के रूप में, संकलक के लिए लूप लेखन के दो तरीके के लिए समान MSIL उत्पन्न होगा।

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

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

2

अन्य उत्तरों के अलावा, में अंतर हो सकता है यदि आपका iint नहीं है। सी ++ में, यदि यह उस वर्ग का ऑब्जेक्ट है जिसमें ऑपरेटर ++() और ++(int) अधिभारित हैं, तो यह एक अंतर और संभवतः एक दुष्प्रभाव बना सकता है। ++iका प्रदर्शन इस मामले में बेहतर होना चाहिए (कार्यान्वयन पर निर्भर)।

+0

अच्छा सी ++ उत्तर, बहुत बुरा सी # उत्तर। आईआईआरसी, सी # में प्रीइंक्रिकमेंट और पोस्टिनक्रिकमेंट के लिए अलग अधिभार नहीं हैं। –

+0

@ बेन वोगेट: हां, आपके पास सी # (http://msdn.microsoft.com/en-us/library/aa691363.aspx) में वृद्धि ऑपरेटर के लिए केवल एक अधिभार हो सकता है। मुझे यह नहीं पता था। पारितोषिक के लिए धन्यवाद। –

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