2009-06-17 13 views
24

के लिए बढ़ाया जावा में, यह तेजी से एक सरणी के माध्यम से पुराने तरीके से पुनरावृति करने के लिए,सबसे तेजी से रास्ता: पाश चर बनाम बयान

for (int i = 0; i < a.length; i++) 
    f(a[i]); 

या अधिक संक्षिप्त फ़ॉर्म का उपयोग करके,

है
for (Foo foo : a) 
    f(foo); 

एक ऐरेलिस्ट के लिए, क्या इसका उत्तर है?

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

+0

क्यों नहीं एक बेंचमार्क चलाएँ:

for(ClassOfElement element : listOfElements) { System.out.println(element.getValue()); } 

यह पहले उत्तर दिया गया? एक चर्चा से ज्यादा सटीक। – Deestan

+0

जब तक कि 'f() 'गायब हो जाता है, तब तक आप अंतर को देखने की संभावना नहीं रखते हैं। – EJP

+0

यह [पहले पूछा गया] [http://stackoverflow.com/questions/256859/is-there-a-performance-difference-between-a-for-loop-and-a-for-each-loop)। – RichardOD

उत्तर

53

यदि आप किसी सरणी के माध्यम से लूपिंग कर रहे हैं, तो इससे कोई फर्क नहीं पड़ता - लूप के लिए बढ़ाया सरणी किसी भी तरह से उपयोग करता है।

public static void main(java.lang.String[]); 
    Code: 
    0: aload_0 
    1: astore_1 
    2: aload_1 
    3: arraylength 
    4: istore_2 
    5: iconst_0 
    6: istore_3 
    7: iload_3 
    8: iload_2 
    9: if_icmpge 31 
    12: aload_1 
    13: iload_3 
    14: aaload 
    15: astore 4 
    17: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 
    20: aload 4 
    22: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    25: iinc 3, 1 
    28: goto 7 
    31: return 

अब एक स्पष्ट सरणी पहुँच का उपयोग करने के लिए इसे बदल:

उदाहरण के लिए, इस कोड पर विचार करें:

public static void main(String[] args) 
{ 
    for (String x : args) 
    { 
     System.out.println(x); 
    } 
} 

जब javap -c Test साथ decompiled हम मिल (main विधि के लिए)

public static void main(String[] args) 
{ 
    for (int i = 0; i < args.length; i++) 
    { 
     System.out.println(args[i]); 
    } 
} 

यह डिकंपाइल:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_0 
    1: istore_1 
    2: iload_1 
    3: aload_0 
    4: arraylength 
    5: if_icmpge 23 
    8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 
    11: aload_0 
    12: iload_1 
    13: aaload 
    14: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    17: iinc 1, 1 
    20: goto 2 
    23: return 

लूप के लिए उन्नत में थोड़ा और सेटअप कोड है, लेकिन वे मूल रूप से वही काम कर रहे हैं। कोई इटरेटर शामिल नहीं हैं। इसके अलावा, मैं उम्मीद करता हूं कि उन्हें और भी समान कोड के लिए JITted प्राप्त करें।

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

21

यह micro-optimization के क्षेत्र में पूरी तरह से गिरता है। यह वास्तव में कोई फर्क नहीं पड़ता। स्टाइलिस्टिक रूप से मैं हमेशा दूसरा पसंद करता हूं क्योंकि यह अधिक संक्षिप्त है, जब तक कि आपको किसी और चीज के लिए लूप काउंटर की आवश्यकता न हो। और इस प्रकार के माइक्रो-ऑप्टिमाइज़ेशन: पठनीयता से कहीं अधिक महत्वपूर्ण है।

कहा जा रहा है कि, एक ऐरेलिस्ट के लिए बहुत अंतर नहीं होगा लेकिन एक लिंक्डलिस्ट दूसरे के साथ अधिक कुशल होगा।

+4

यह एक सरणी के लिए एक इटरेटर का उपयोग नहीं करेगा। –

+1

पहली शैली इंटीजर.एमएक्स संख्या पुनरावृत्तियों तक सीमित है, जबकि दूसरा नहीं है। – Chii

+2

दूसरा भी इस तरह से सीमित है क्योंकि सरणी में तत्वों की अधिकतम Integer.MAX_VALUE संख्या होती है और एक ऐरेलिस्ट को सरणी द्वारा समर्थित किया जाता है। – cletus

6

इसे मापें। सभी प्रदर्शन-प्रश्नों का उत्तर वीएम-संस्करण, प्रोसेसर, मेमोरी-स्पीड, कैश इत्यादि पर निर्भर हो सकता है। इसलिए आपको इसे अपने विशेष मंच के लिए मापना होगा।

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

1

एक सरणी पर, या RandomAccess संग्रह आप ऐसा करके गति में एक छोटे से वृद्धि प्राप्त कर सकते हैं:

List<Object> list = new ArrayList<Object>(); 

for (int i=0, d=list.size(); i<d; i++) { 
    something(list.get(i)); 
} 

लेकिन मैं सामान्य रूप में चिंता नहीं करता। इस तरह के अनुकूलन आपके कोड में 0.1% से अधिक अंतर नहीं बनाते हैं। -prof के साथ जावा को आविष्कार करने का प्रयास करें ताकि यह देखने के लिए कि आपका कोड वास्तव में अपना समय कहां खर्च कर रहा है।

0

फोर्क-जॉइन फ्रेमवर्क के समांतर आरे का उपयोग करना भी तेज़ है (यदि आपके पास पर्याप्त डेटासेट है)।

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