2013-04-10 8 views
6

के लिए एक ओवरकिल है, मैं सहमत हूं कि फ़ोरैच लूप टाइपिंग को कम करता है और पठनीयता के लिए अच्छा है।जावा फोरैच लूप बार-बार निष्पादन

थोड़ा बैकअप, मैं कम विलंबता अनुप्रयोग विकास पर काम करता हूं और प्रति सेकंड प्रक्रिया के लिए 1 मिलियन पैकेट प्राप्त करता हूं। एक लाख पैकेट के माध्यम से Iterating और इस जानकारी को अपने श्रोताओं को भेजना। मैं श्रोताओं के सेट के माध्यम से फिर से शुरू करने के लिए foreach पाश का उपयोग कर रहा था।

प्रोफाइलिंग करना मुझे लगता है कि इटरेटर ऑब्जेक्ट्स फ़ोरैच लूप निष्पादित करने के लिए बनाए गए हैं। इंडेक्स आधारित फोरच में फ़ोरैच लूप को कनवर्ट करना मैंने संख्या को कम करके वहां बनाई गई वस्तुओं की संख्या में एक बड़ी गिरावट देखी। जीसी और बढ़ते आवेदन थ्रुपुट के।

संपादित: (भ्रम के लिए क्षमा करें, यह क्यू अधिक स्पष्ट बनाने) उदाहरण मैं (फिक्स्ड आकार) श्रोताओं की सूची और मैं के माध्यम से इस forloop एक लाख गुना एक दूसरे पाश है के लिए। जावा में एक overkill foreach है?

उदाहरण:

for(String s:listOfListeners) 
{ 
    // logic 
} 

तुलना

for (int i=0;i<listOfListeners.size();i++) 
{ 
    // logic 
} 
कोड के लिए

Profiled स्क्रीनशॉट को

for (int cnt = 0; cnt < 1_000_000; cnt++) 
{ 
    for (String string : list_of_listeners) 
    { 
     //No Code here 
    } 
} 

enter image description here

+1

रूपरेखा के लिए आप पर अच्छा है, लेकिन क्या तुम सच में अपने प्रश्न reword चाहिए इसलिए लोग इसे गलत व्याख्या नहीं करते हैं - आप इस लूप को 1000,000 बार (पैकेट की संख्या) श्रोताओं की अपेक्षाकृत कम संख्या में सूचीबद्ध कर रहे हैं (list.size) –

+1

@ AK4749: तो "सूची का आकार लगभग दस लाख ऑब्जेक्ट स्ट्रीमिंग है" पूर्ण लाल हेरिंग? –

+0

@ AK4749 * एक लाख पैकेट के माध्यम से इटरेट करना और इस जानकारी को अपने श्रोताओं को भेजना *। इसका मतलब है पैकेट की एक बड़ी सूची और श्रोताओं की एक छोटी सूची (अपेक्षाकृत)। – maba

उत्तर

10

संपादित करें: उत्तर देना बेहद घ यदि

उदाहरण के लिए मेरे पास श्रोताओं (निश्चित आकार) की सूची है और मैं इस माध्यम से एक लाख बार एक बार लूप के माध्यम से लूप करता हूं। जावा में एक overkill foreach है?

यह निर्भर करता है - अपने रूपरेखा वास्तव में दिखाता है कि अतिरिक्त आवंटन महत्वपूर्ण कर रहे हैं? जावा आवंटक और कचरा कलेक्टर प्रति सेकंड काम के लॉट कर सकते हैं।

दूसरे शब्दों में कहें के लिए, अपने चरणों का होना चाहिए:

  1. अपने कार्यात्मक जरूरतों के साथ व्यवस्थित किया प्रदर्शन लक्ष्यों
  2. सरल कोड लिखें आप अपने कार्यात्मक जरूरतों
  3. उपाय है कि कोड को पूरा करता है को प्राप्त करने के कर सकते हैं कार्यात्मक जरूरतों
  4. यदि ऐसा नहीं होता: बाहर काम करने के
    • प्रोफ़ाइल जहां Opti को मज़े
    • परिवर्तन करें
    • यह देखने के लिए फिर से परीक्षण चलाएं कि क्या वे आपके सार्थक मीट्रिक में महत्वपूर्ण अंतर डालते हैं (आवंटित वस्तुओं की संख्या शायद सार्थक मीट्रिक नहीं है; श्रोताओं की संख्या जो आप शायद संभाल सकते हैं)
    • चरण 3 पर वापस जाएं।

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


आकार के चारों ओर एक मिलियन वस्तुओं में स्ट्रीमिंग है।

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

प्रोफाइलिंग करना मुझे लगा कि फोरैच लूप निष्पादित करने के लिए कई इटरेटर ऑब्जेक्ट्स बनाए गए हैं।

नहीं? केवल एकल इटरेटर ऑब्जेक्ट बनाया जाना चाहिए। As per the JLS:

बयान के लिए बढ़ाया फार्म के बयान के लिए एक बुनियादी के बराबर है:

for (I #i = Expression.iterator(); #i.hasNext();) { 
     VariableModifiersopt TargetType Identifier = 
      (TargetType) #i.next(); 
     Statement 
    } 

आप देख सकते हैं, कि iterator() कॉल विधि एक बार, और फिर hasNext() कॉल और प्रत्येक पुनरावृत्ति पर next() पर।

क्या आपको लगता है कि अतिरिक्त ऑब्जेक्ट आवंटन वास्तव में आपके प्रदर्शन को काफी नुकसान पहुंचाएगा?

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

+1

उम, ठीक है, मैं गलत हो सकता हूं, लेकिन मुझे लगता है कि ज्यादातर लोग अपने अस्पष्ट सवाल को बहुत सावधानी से नहीं पढ़ रहे हैं। वह वास्तव में, इस लूप को 1000000 बार बुला रहा है, क्योंकि लूप श्रोताओं के सेट के लिए है। –

+0

@ जॉन्सकेट मुझे इसे थोड़ा सा बदलने दें। फोरैच का विचलन एक विधि में है कॉल कॉल (सूची एल) और मैं सूची को तर्क के रूप में पास करता हूं। तत्वों को लगातार इस सूची में जोड़ा जाता है और इस सूची में तत्वों के प्रत्येक जोड़े को कॉल कॉल कॉल करने के लिए कॉल किया जाएगा (सूची एल) इस मामले में यह कॉल के लिए इटेटरेटर ऑब्जेक्ट नहीं बनाता है? –

+0

@ AK4749: मैंने इसे कई बार सावधानी से पढ़ा है, और यह अभी भी मेरे लिए अविश्वसनीय रूप से अस्पष्ट है।लेकिन यदि सूची का आकार 1 मिलियन ऑब्जेक्ट्स है, तो यह अभी भी असंभव है कि उस पर फिर से चलने पर, इटरेटर बनाया गया बाधा होगा। –

6

"foreach" पाश केवल एक Iterator ऑब्जेक्ट बनाता है, जबकि दूसरा पाश कोई भी नहीं बनाता है। यदि आप कई निष्पादित कर रहे हैं, तो कई अलग-अलग लूप जो प्रत्येक बार कुछ बार निष्पादित करते हैं, फिर हां, "foreach" अनावश्यक रूप से महंगा हो सकता है। अन्यथा, यह सूक्ष्म अनुकूलन है।

+0

हां, मेरा मानना ​​है कि वास्तव में उसका उपयोग-मामला दूसरा है, जहां लूप के अपेक्षाकृत छोटे से 1,000,000 कॉल हैं। मेरा मानना ​​है कि इस संबंध में उनके प्रश्न –

0

मुझे नहीं लगता कि आपको यहां प्रभावशीलता के बारे में चिंता करनी चाहिए।

अधिकांश समय आपके वास्तविक एप्लिकेशन तर्क (इस मामले में - आप लूप के अंदर क्या करते हैं) द्वारा खपत किया जाता है।

तो, मैं यहां सुविधा के लिए भुगतान की गई कीमत के बारे में चिंता नहीं करता।

+0

में काफी अस्पष्ट हैं, जबकि यह 90% मामलों में सच है, मुझे नहीं पता कि आप एप्लिकेशन तर्क को जानने के बिना यह कह सकते हैं या नहीं - ढेर आधारित मेमोरी आवंटन में बड़े प्रदर्शन की कमी होती है जब कॉल किया जा रहा है कोड हॉटस्पॉट –

0

क्या यह तुलना भी उचित है?आप Iterator बनाम get(index)

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

1

संपादित करें: प्रश्न मैंने इतना बदल दिया है क्योंकि मैंने अपना जवाब लिखा था कि मुझे यकीन नहीं है कि मैं इस समय क्या जवाब दे रहा हूं।

list.get(i) साथ सामान अवलोकन किया जा रहा वास्तव में बहुत धीमी हो सकता है अगर यह एक लिंक्ड सूची है, क्योंकि प्रत्येक देखने के लिए, यह सूची पार करने के लिए है, जबकि इटरेटर स्थिति याद रखता है।

उदाहरण:

list.get(0) will get the first element 
list.get(1) will first get the first element to find pointer to the next 
list.get(2) will first get the first element, then go to the second and then to the third 
etc. 

तो एक पूर्ण पाश करने के लिए, आप वास्तव में इस तरह से तत्वों से अधिक पाशन कर रहे हैं:

0 
0->1 
0->1->2 
0->1->2->3 
etc. 
+1

यह एक * लिंक * सूची मान रहा है ... मुझे इसका कोई सबूत नहीं दिख रहा है। –

+0

@ जोन्स स्केट सच, निर्दिष्ट किया जाना चाहिए था, अब तय किया गया है। ओपी ने इस्तेमाल किए गए कार्यान्वयन को निर्दिष्ट करते हुए एक सूची w/o का उल्लेख किया। – Matsemann

+0

हां, और मेरे अनुभव में 'ArrayList' का प्रयोग जावा में 'लिंक्डलिस्ट' से अधिक बार किया जाता है। –

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