दिलचस्प पोस्ट
SQLite पैरामीटर – टैबलेनम पैरामीटर के रूप में अनुमति नहीं दे रहा है मेरे आईआईएस होस्टेड साइट को अपने नेटवर्क पर अन्य मशीनों पर देखना स्विफ्ट – डिवाइस का आईपी पता प्राप्त करें Virtualenv के साथ पीआईपी के माध्यम से स्थापित नहीं किया जा सकता हार्ड डिस्क सीरियल नंबर प्राप्त करें PyCharm के भीतर (एना) कोंडा का उपयोग करना आर में आरप्रोफ का कुशलतापूर्वक उपयोग कैसे करें? कार्यक्रम में एक स्थैतिक 'मेन' ​​विधि एक प्रवेश बिंदु के लिए उपयुक्त नहीं है NTFS (Windows XP और Windows Vista) में अधिकतम फ़ाइल नाम की लंबाई? शेल स्क्रिप्ट की तुलना अक्सर क्यों एक्स $ VAR = xyes का उपयोग करते हैं? HTML कैनवास पर पाठ की ऊँचाई कैसे प्राप्त कर सकते हैं? हेडर और क्लाइंट लायबरी छोटे संस्करण बेमेल कार्य रिक्त या रिक्त ऑब्जेक्ट वापस लेना चाहिए? कॉरस अनुरोध Safari में काम नहीं कर रहा है एंड्रॉइड खींचें / दृश्य का एनिमेशन

लूप अनुकूलन के लिए

List<String> flowers = new ArrayList<String>(); 

लूप के लिए मेरा वर्तमान में इस तरह दिखता है …

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

या मुझे इसे नीचे दिए गए कोड की तरह देखने के लिए इसे बदलना चाहिए I

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

जो अधिक performant है (संभालने मैं फूलों की एक बड़ी सरणी है), मैं अनुमान लगा रहा हूँ यह बाद का होना चाहिए।

Solutions Collecting From Web of "लूप अनुकूलन के लिए"

प्रत्येक पाश [अधिक पठनीय] के लिए उपयोग करना बेहतर है

 for (Flower flower :flowers){ //... } 

मैंने निम्नलिखित कोड के लिए javap का उपयोग करने के निर्देश दिए हैं:

 public void forLoop1() { List<String> lst = new ArrayList<String>(); for (int i = 0; i < lst.size(); i++) { System.out.println("hi"); } } public void forLoop2() { List<String> lst = new ArrayList<String>(); int size = lst.size(); for (int i = 0; i < size; i++) { System.out.println("hi"); } } 

 public void forLoop1(); Code: 0: new #2; //class java/util/ArrayList 3: dup 4: invokespecial #3; //Method java/util/ArrayList."<init>":()V 7: astore_1 8: iconst_0 9: istore_2 10: iload_2 11: aload_1 12: invokeinterface #4, 1; //InterfaceMethod java/util/List.size:()I 17: if_icmpge 34 20: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 23: ldc #6; //String hi 25: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/Str ing;)V 28: iinc 2, 1 31: goto 10 34: return public void forLoop2(); Code: 0: new #2; //class java/util/ArrayList 3: dup 4: invokespecial #3; //Method java/util/ArrayList."<init>":()V 7: astore_1 8: aload_1 9: invokeinterface #4, 1; //InterfaceMethod java/util/List.size:()I 14: istore_2 15: iconst_0 16: istore_3 17: iload_3 18: iload_2 19: if_icmpge 36 22: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 25: ldc #6; //String hi 27: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/Str ing;)V 30: iinc 3, 1 33: goto 17 36: return 

यह मेरे लिए अनुकूल नहीं है

जावा संस्करण "1.6.0_22" जावा (टीएम) एसई रनटाइम एन्वायरमेंट (1.6.0_22-बी 04) का निर्माण जावा हॉटस्पॉट (टीएम) क्लाइंट वीएम (17.1-बी 0 3, मिश्रित मोड, साझाकरण)

इसलिए यदि आपको दो का उल्लेख करने की आवश्यकता है, तो दूसरे के लिए जाएं, लेकिन मैं व्यक्तिगत रूप for-each जाना होगा


प्रत्येक प्रदर्शन के लिए

आईएसओ 46 में प्रभावी जावा में यहोशू ब्लोच द्वारा:

रिलीज 1.5 में पेश किए गए प्रत्येक लूप के लिए, अव्यवस्था से छुटकारा पाता है और त्रुटि के लिए इटरेटर या इंडेक्स वैरिएबल पूरी तरह से छिपाकर मौका मिलता है। परिणामस्वरूप मुहावरे संग्रह और सरणियों के लिए समान रूप से लागू होता है:

 // The preferred idiom for iterating over collections and arrays for (Element e : elements) { doSomething(e); } 

जब आप बृहदान्त्र (:) को देखते हैं, तो इसे "इन" के रूप में पढ़िए। इस प्रकार, ऊपर दिए गए लूप "प्रत्येक तत्व के लिए तत्वों में" के रूप में पढ़ता है। ध्यान दें कि हर पाश के लिए, यहां तक ​​कि सरणियों के लिए कोई प्रदर्शन जुर्माना नहीं है । वास्तव में, यह कुछ परिस्थितियों में पाश के लिए सामान्य पर एक मामूली प्रदर्शन लाभ प्रदान कर सकता है, क्योंकि यह केवल एक बार सरणी अनुक्रमणिका की सीमा की गणना करता है। जब आप इसे हाथ से (आइटम 45) कर सकते हैं, प्रोग्रामर हमेशा ऐसा नहीं करते हैं।


यह भी देखें

  • वहाँ है-एक प्रदर्शन-अंतर-बीच एक के लिए लूप और एक के लिए प्रत्येक लूप

कहने के लिए क्षमा करें, लेकिन जिगर का उत्तर गलत नहीं है। यह सही जवाब है। (टीडडर; का प्रयोग न करें for : each )।

 import java.util.ArrayList; import java.util.List; public class LoopTest { public static void main(String s[]) { long start, end; List<Integer> a = new ArrayList<Integer>(); for (int i = 0; i < 2500000; i++) { a.add(i); } ///// TESTING FOR : EACH LOOP start = System.currentTimeMillis(); for (Integer j : a) { int x = j + 3; } end = System.currentTimeMillis(); System.out.println(end - start + " milli seconds for [ Integer j : a ] "); ////// TESTING DEFAULT LOOP start = System.currentTimeMillis(); for (int i = 0; i < a.size(); i++) { int x = a.get(i) + 3; } end = System.currentTimeMillis(); System.out.println(end - start + " milli seconds for [ int i = 0; i < a.length; i++ ] "); ////// TESTING SLIGHTLY OPTIMIZED LOOP start = System.currentTimeMillis(); int size = a.size(); for (int i = 0; i < size; i++) { int x = a.get(i) + 3; } end = System.currentTimeMillis(); System.out.println(end - start + " milli seconds for [ int i = 0; i < size; i++ ] "); //// TESTING MORE OPTIMIZED LOOP start = System.currentTimeMillis(); for (int i = size; --i >= 0;) { int x = a.get(i) + 3; } end = System.currentTimeMillis(); System.out.println(end - start + " milli seconds for [ int i = size; --i >= 0; ] "); } } 

परिणाम:

 96 milli seconds for [ Integer j : a ] 57 milli seconds for [ int i = 0; i < a.length; i++ ] 31 milli seconds for [ int i = 0; i < size; i++ ] 31 milli seconds for [ int i = size; --i >= 0; ] 

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

हालांकि इनमें से कुछ ऑप्टिमाइज़ेशन जेवीएम-आश्रित (और कुछ जेआईटी के साथ हो सकते हैं) हो सकते हैं, यह जानना महत्वपूर्ण है कि जावा क्या करता है और जावा क्या नहीं करता।

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

यदि प्रदर्शन महत्वपूर्ण है, तो सादे काउंटर लूप का उपयोग करें, हालांकि 98% मामलों के लिए, कोड की स्पष्टता और सादगी बहुत अधिक महत्वपूर्ण है (जैसे 1000x या अधिक) और आपको प्रत्येक लूप का उपयोग करना चाहिए।

@ डेविड का कहना है कि काउंटर का इस्तेमाल तेजी से होता है, लेकिन मैं बताता हूं कि 10,000 प्रविष्टियों के लिए भी अंतर उप माइक्रोसेंड है।

यदि आपके पास 10,000 से अधिक प्रविष्टियों का संग्रह है तो यह बहुत संभावना है कि आपको हर संभव संभावना पर चलने वाले जानवरों को नहीं चलाना चाहिए। मानचित्र की तरह लुकअप के साथ एक संग्रह अधिक होने की संभावना अधिक है जो आपके मन में है यदि आपके पास 10,000 से कम प्रविष्टियां हैं तो प्रदर्शन महत्वपूर्ण होने की संभावना कम है।

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

 for (int i = 0, size = flowers.size(); i < size; i++) { ... } 

जावा भाषा विनिर्देश (14.14.1) से:

बयान के लिए मूल कुछ आरंभीकरण कोड निष्पादित करता है , फिर अभिव्यक्ति के मूल्य झूठे होने तक एक अभिव्यक्ति , एक वक्तव्य और कुछ अपडेट कोड को बार-बार निष्पादित करता है।

अभिव्यक्ति है i < flowers.size() आपके पहले उदाहरण में और इसका मूल्यांकन प्रत्येक पुनरावृत्ति में एक बार किया जाता है। आपके विशेष मामले में यह एक उल्लेखनीय अंतर नहीं बना सकता, क्योंकि ArrayList पर flowers.getSize() एक बहुत ही कम विधि है लेकिन, सामान्य तौर पर, यदि अभिव्यक्ति का परिणाम प्रत्येक पुनरावृत्ति और महंगी के लिए होता है, तो पूर्व गणना करें।

परिणाम : यह एक जावा आभासी मशीन के हर कार्यान्वयन में एक ही उत्पादन का उत्पादन करना है और यह साबित करता है कि अभिव्यक्ति प्रत्येक आवृत्ति में एक बार मूल्यांकन करती है:

 int counter2 = 10; for (int counter1 = 0; counter1 < counter2; counter1++) { System.out.println(counter1 + ", " + counter2); counter2--; } 

आउटपुट:

 0, 10 1, 9 2, 8 3, 7 4, 6 

सबसे अच्छा विकल्प है

 [ int i = 0; i < size; i++ ] 

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

 1.6 -server 7.968242071 milli seconds for [ Integer j : a ] 7.206275775999999 milli seconds for [ int i = 0; i < a.length; i++ ] 1.5864E-5 milli seconds for [ int i = 0; i < size; i++ ] 14.774186076999998 milli seconds for [ int i = size; --i >= 0; ] -client 83.36101683999999 milli seconds for [ Integer j : a ] 44.288568631 milli seconds for [ int i = 0; i < a.length; i++ ] 2.3191E-5 milli seconds for [ int i = 0; i < size; i++ ] 24.826621246 milli seconds for [ int i = size; --i >= 0; ] 1.7 -server 7.029150422 milli seconds for [ Integer j : a ] 6.6269827779999995 milli seconds for [ int i = 0; i < a.length; i++ ] 1.3852E-5 milli seconds for [ int i = 0; i < size; i++ ] 13.842110377 milli seconds for [ int i = size; --i >= 0; ] 13.868426141 milli seconds for [ int i = a.size()-1; i >= 0; i-- ] 1.6618000000000003E-5 milli seconds for [ int i = 0; i < a.size(); i++ ] -client 7.382479727 milli seconds for [ Integer j : a ] 6.748068759 milli seconds for [ int i = 0; i < a.length; i++ ] 1.4162999999999998E-5 milli seconds for [ int i = 0; i < size; i++ ] 13.951547335999999 milli seconds for [ int i = size; --i >= 0; ] 13.929234053999998 milli seconds for [ int i = a.size()-1; i >= 0; i-- ] 1.6873E-5 milli seconds for [ int i = 0; i < a.size(); i++ ] 

टेस्ट कोड:

 public static void main(String s[]) { long start=0, end = 0, delta = 0; //int[] a = new int[2500000]; List<Integer> a = new ArrayList<Integer>(); int x = 0; for (int i = 0; i < 2500000; i++) { a.add(i); } start=0; end = 0; delta = 0; for (int ctr = 0; ctr < 1000; ctr++) { start = System.nanoTime(); for (Integer j : a) { x = j + 3; } end = System.nanoTime(); delta += end - start; } System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ Integer j : a ] "); start=0; end = 0; delta = 0; for (int ctr = 0; ctr < 1000; ctr++) { start = System.nanoTime(); for (int i = 0; i < a.size(); i++) { x = a.get(i) + 3; } end = System.nanoTime(); delta += end - start; } System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = 0; i < a.length; i++ ] "); int size = a.size(); start=0; end = 0; delta = 0; for (int ctr = 0; ctr < 1000; ctr++) { start = System.currentTimeMillis(); for (int i = 0; i < size; i++) { x = a.get(i) + 3; } end = System.currentTimeMillis(); delta += end - start; } System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = 0; i < size; i++ ] "); start=0; end = 0; delta = 0; for (int ctr = 0; ctr < 1000; ctr++) { start = System.nanoTime(); for (int i = size; --i >= 0;) { x = a.get(i) + 3; } end = System.nanoTime(); delta += end - start; } System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = size; --i >= 0; ] "); start=0; end = 0; delta = 0; for (int ctr = 0; ctr < 1000; ctr++) { start = System.nanoTime(); for (int i = a.size()-1; i >= 0; i--) { x = a.get(i) + 3; } end = System.nanoTime(); delta += end - start; } System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = a.size()-1; i >= 0; i-- ] "); start=0; end = 0; delta = 0; for (int ctr = 0; ctr < 1000; ctr++) { start = System.currentTimeMillis(); for (int i = 0; i < a.size(); i++) { x = a.get(i) + 3; } end = System.currentTimeMillis(); delta += end - start; } System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = 0; i < a.size(); i++ ] "); System.out.println(x); } 

यह सिर्फ एक स्पष्टीकरण है कि यह कैसे स्थिति है

मैं for (int i = 0; i < list.size(); i++) के लूप के for (int i = 0; i < list.size(); i++) "सामान्य" के निष्पादन का परीक्षण किया और for (int i = -1, size = list.size(); ++i < size;) लिए लूप के for (int i = -1, size = list.size(); ++i < size;) अनुकूलित माइक्रो for (int i = -1, size = list.size(); ++i < size;) मैं कमांड लाइन से ग्रहण में दोनों परीक्षण चलाया और एक विशाल अंतर देखा

एक्लिप्स में चलने के परिणाम:

 Time for Original: 32552 ms Time for MicroOptimized 32707 ms Fastest Loop: Original Slowest loop takes 0.47616121897272057% more time 

कमांडलाइन से चलने के परिणाम:

 Time for Original: 274489 ms Time for MicroOptimized 30516 ms Fastest Loop: MicroOptimized Slowest loop takes 799.4920697339101% more time 

तो ग्रहण में, लूप के लिए दोनों एक ही समय लेते हैं, लेकिन जब कमांड लाइन से चलाया जाता है, मूल संस्करण माइक्रोप्रिटिमाइज़ संस्करण से 800% अधिक समय लेता है। अंतर की भयावहता मेरे मन को उड़ा देती है मुझे लगता है कि ग्रहण एक अलग जेवीएम का उपयोग करता है जो कुछ स्मार्ट अनुकूलन युक्तियां लागू करता है I

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

पूर्णता के लिए, यह वह कोड है जो मैंने दौड़ा था:

 public static void main(String[] args) { List<Byte> list = initializeList(); byte value = 0; final int NUM_LOOPS = 100; long startOriginal, startOptimized, endOriginal, endOptimized; startOptimized = System.currentTimeMillis(); for (int j = 0; j < NUM_LOOPS; j++) { for (int i = -1, size = list.size(); ++i < size;) { value = list.get(i); } } endOptimized = System.currentTimeMillis(); startOriginal = System.currentTimeMillis(); for (int j = 0; j < NUM_LOOPS; j++) { for (int i = 0; i < list.size(); i++) { value = list.get(i); } } endOriginal = System.currentTimeMillis(); System.out.println(value); printResults(startOriginal, endOriginal, startOptimized, endOptimized); } private static void printResults(long startOriginal, long endOriginal, long startOptimized, long endOptimized) { long timeOriginal = endOriginal - startOriginal; long timeOptimized = endOptimized - startOptimized; long diff = Math.abs(timeOriginal - timeOptimized); long min = Math.min(timeOriginal, timeOptimized); System.out.println("Time for Original: " + timeOriginal + " ms" + " Time for MicroOptimized " + timeOptimized + " ms"); System.out.println("Fastest Loop: " + ((timeOriginal < timeOptimized) ? "Original" : "MicroOptimized")); System.out.println("Slowest loop takes " + ((double) 100 * diff / min) + "% more time"); } public static List<Byte> initializeList(){ List<Byte> list = new ArrayList<Byte>(); final Byte ONE = new Byte((byte) 1); for (int i = 0; i < Integer.MAX_VALUE / 10; i++) { list.add(ONE); } return list; } } 

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

मैं इटरेटर निर्माण का उपयोग करने का सुझाव दूंगा (जैसा कि पहले ही सुझाव दिया गया है)

 For (Flower flower: flowers) { ... 

यह स्पष्ट, लचीला और भविष्यवाणी है

इस समस्या पर मेरा दृष्टिकोण थोड़ा अलग है मेरे लिए, यह कोई फर्क नहीं पड़ता कि आप किस पद्धति का चुनाव करते हैं इसका कारण यह है कि "प्रदर्शन सुधार" आपको सर्वोत्तम अनुकूलित पद्धति में मिलेगा, यह 2,500,000 चलने के लिए ~ 50ms होगा! (डेविड के पद के अनुसार) और जाहिर तौर पर यह सुधार ऐसा कुछ नहीं है जैसे आप ऑप्टिमाइज्ड समाधान खोजने में अपना बहुमूल्य समय बर्बाद करना चाहते हैं।

(लेकिन फिर भी, ओपी के मूल प्रश्न के अनुसार, मैं भी आखिरी दृष्टिकोण का सुझाव देना चाहूंगा।)

मुझे पता है कि जवाब थोड़ा अजीब और अनौपचारिक है, लेकिन यह वास्तविकता है

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

 for (Object object : aCollection) { // Do something here } 

यदि सूचकांक की आवश्यकता है तो: उपरोक्त दो रूपों के बीच चयन करने के लिए: दूसरा बेहतर होता है क्योंकि आप जाँच करने के लिए एक स्थानीय चर का प्रयोग कर रहे हैं। जब विधि से बाहर निकलता है तो चर को ढेर के कचरा हो या चले गए।

साथ ही, अगर आपको आश्चर्य है कि किसी स्रोत कॉल के रूप में किसी विधि कॉल का उपयोग करने पर कोई निष्पादन प्रभाव पड़ता है या नहीं यही है – विधि को कई बार कहा जाएगा – जवाब नहीं है यहां एक उदाहरण है:

 import java.util.*; public class TestForeach { public static void main (String[] args) { for (String s : getStrings()) { System.out.println("The string was: "+s); } } private static List<String> getStrings() { System.out.println("IN GET STRINGS"); return Arrays.asList("A","B","C"); } } 

इसका परिणाम निम्न होगा:

 IN GET STRINGS The string was: A The string was: B The string was: C 

इसलिए, विधि को केवल एक बार कहा जाएगा।

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

तो पहले कोड स्निपेट के लिए जाएं

 for (int i = 0; i < flowers.size(); i++) { ... } 
 String d = JOptionPane.showInputDialog("enter start"); int s = Integer.parseInt(d); String h = JOptionPane.showInputDialog("enter the end"); int z = Integer.parseInt(h); for (int a = 1 ; a<10 ; a++) { if (a%2 == 0 ) { JOptionPane.showMessageDialog(null, a); System.out.print(a); } }