2013-10-04 9 views
7

जावा लूप में, if कथन के बजाय boolean ध्वज का उपयोग करना अधिक कुशल है?क्या यह ध्वज या एक खंड का उपयोग करने के लिए अधिक कुशल है?

कोड के इन दो बिट्स पर एक नज़र डालें।

एक ध्वज का उपयोग करना:

public boolean isSomethingForAnyone() { 
    boolean flag = false; 
    for (Item item : listOfItems) { 
     flag = flag || item.isSomething(); 
    } 
    return flag; 
} 

एक if बयान का उपयोग करना: if बयान के साथ

public boolean isSomethingForAnyone() { 
    for (Item item : listOfItems) { 
     if (item.isSomething()) 
      return true; 
    } 
    return false; 
} 

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

+0

प्रत्येक के लिए नियमित रूप से लूप के लिए धीमी नहीं है। – JNL

+1

पहले सभी तत्वों पर हमेशा पुनरावृत्त होगा; दूसरा आइटम बंद हो जाएगा जब एक आइटम सच है। –

उत्तर

4

कोड के दो टुकड़े काफी समकक्ष नहीं हैं।

भले ही आप केवल item.isSomething() रूप में कई बार फोन के रूप में आप (अपने मूल जवाब के विपरीत) की जरूरत है, पहले संस्करण अभी भी संग्रह के बाकी हिस्सों में पुनरावृति करने की कोशिश कर रखता है।

Item.isSomething() के कार्यान्वयन की कल्पना करें जिसमें संग्रह मिला है जिसमें आइटम मिला है (यदि यह true देता है)। उस बिंदु पर, कोड का पहला टुकड़ा ConcurrentModificationException फेंक देगा, यह मानते हुए कि यह एक "नियमित" संग्रह है - जबकि कोड का दूसरा भाग केवल true लौटाएगा।

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

कौन सा आप पाते हैं और अधिक पठनीय अलग बात है - यह संभव है कि दक्षता महत्वपूर्ण नहीं होंगे, हालांकि इस संदर्भ पर निर्भर करता है। व्यक्तिगत रूप से मुझे दूसरा संस्करण अधिक पठनीय के साथ-साथ अधिक कुशल लगता है, इसलिए मैं हमेशा इसका उपयोग करता हूं। (ठीक है, मैं if कथन के शरीर के चारों ओर ब्रेसिज़ जोड़ूंगा, लेकिन यह सब कुछ है।)

+0

मुझे लगता है कि मानक कोडिंग शैली मान लेगी कि 'isX' नामक एक विधि शुद्ध होगी यानी कोई दुष्प्रभाव नहीं है। – selig

+0

@selig हां, यही मेरा मतलब था। – Pietu1998

+0

@selig: हां, यह * हमें * बनाने के लिए एक उचित धारणा है - लेकिन ऑप्टिमाइज़र के लिए उस धारणा को बनाने और लूप को जल्दी समाप्त करने के लिए उचित नहीं होगा। (यह संभव है कि वास्तव में एक स्मार्ट जेआईटी इसे देख सके, लेकिन ऐसा लगता है कि यह बहुत ही असंभव है। मुझे नहीं लगता कि यह अनुकूलित करने के लिए एक बहुत ही सामान्य स्थिति है।) –

0

क्या आप इस लूप सचमुच एक बिलियन बार कर रहे हैं? यदि नहीं, तो अंतर मापने के लिए शायद असंभव है।

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

0

यदि आप जानना चाहते हैं कि आपकी मशीन पर 'तेज' कौन सा है तो इसे चलाएं।

यदि हम जानना चाहते हैं कि प्रदर्शन करने के लिए और कौन से निर्देश लेते हैं तो हम बाइटकोड देख सकते हैं।

पहली विधि के लिए हम इस (javap -c फोन)

Code: 
    0: iconst_0  
    1: istore_1  
    2: getstatic  #2     // Field listOfItems:Ljava/util/List; 
    5: invokeinterface #3, 1   // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 
    10: astore_2  
    11: aload_2  
    12: invokeinterface #4, 1   // InterfaceMethod java/util/Iterator.hasNext:()Z 
    17: ifeq   50 
    20: aload_2 
    21: invokeinterface #5, 1   // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 
    26: checkcast  #6     // class Item 
    29: astore_3  
    30: iload_1  
    31: ifne   41 
    34: aload_3  
    35: invokevirtual #7     // Method Item.isSomething:()Z 
    38: ifeq   45 
    41: iconst_1  
    42: goto   46 
    45: iconst_0  
    46: istore_1  
    47: goto   11 
    50: iload_1  
    51: ireturn 

हम पाश के भीतरी इलाकों में रुचि रखते हैं मिल अर्थात लाइनों 29-46 (लाइनों 11-26 इटरेटर सामान हैं)।तो लगभग 10 निर्देश।

Code: 
     0: getstatic  #2     // Field listOfItems:Ljava/util/List; 
     3: invokeinterface #3, 1   // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 
     8: astore_1  
     9: aload_1  
     10: invokeinterface #4, 1   // InterfaceMethod java/util/Iterator.hasNext:()Z 
     15: ifeq   40 
     18: aload_1  
     19: invokeinterface #5, 1   // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 
     24: checkcast  #6     // class Item 
     27: astore_2  
     28: aload_2  
     29: invokevirtual #7     // Method Item.isSomething:()Z 
     32: ifeq   37 
     35: iconst_1  
     36: ireturn  
     37: goto   9 
     40: iconst_0  
     41: ireturn  

ब्याज की तर्ज 27-37 हैं:

दूसरी विधि के लिए हम इस मिलता है। तो 7 निर्देश।

एक बिंदु बिंदु से दूसरी विधि शीर्ष पर आती है (ध्यान दें कि हम मानते हैं कि सभी स्टैक ऑपरेशन करने के लिए एक ही समय लगता है)।

+0

बाइट कोड को देखते हुए वास्तव में क्या होता है, या कौन से निर्देश नहीं हैं वास्तव में निष्पादित। आप यह मानकर * बहुत, बहुत * गलत जा सकते हैं कि बाइट कोड निष्पादित है। यह आश्चर्यजनक है कि एक जेआईटी कंपाइलर कुछ परिस्थितियों में अनुकूलित कर सकता है - लेकिन मुझे आश्चर्य होगा अगर जेआईटी ने दो लूप समकक्ष बनाने के लिए * यह * कोड अनुकूलित किया। –

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