.NET में, कौन सा लूप तेज चलता है, 'फॉर' या 'फॉरच'?


345

C # / VB.NET / .NET में, कौन सा लूप तेजी से चलता है, forया foreach?

जब से मैंने पढ़ा है कि एक forलूप एक लूप की तुलना में तेजी से काम करता foreachहै, बहुत समय पहले मैंने मान लिया था कि यह सभी संग्रह, सामान्य संग्रह, सभी सरणियों आदि के लिए सही है।

मैंने Google को देखा और कुछ लेख पाए, लेकिन उनमें से अधिकांश अनिर्णायक हैं (लेखों पर टिप्पणी पढ़ें) और समाप्त हो गए।

आदर्श क्या होगा जो प्रत्येक परिदृश्य को सूचीबद्ध करता है और उसी के लिए सबसे अच्छा समाधान है।

उदाहरण के लिए (सिर्फ एक उदाहरण कि यह कैसा होना चाहिए):

  1. 1000+ स्ट्रिंग्स की सरणी को पुनरावृत्त करने के लिए - forसे बेहतर हैforeach
  2. IList(गैर सामान्य) स्ट्रिंग्स पर पुनरावृति के लिए - foreachसे बेहतर हैfor

उसी के लिए वेब पर पाए गए कुछ संदर्भ:

  1. इमैनुअल शैंज़र द्वारा मूल भव्य पुराना लेख
  2. कोडप्रोटोक फॉरेक्स बनाम। के लिये
  3. ब्लॉग - करने के लिए foreachया नहीं foreach, यह सवाल है
  4. ASP.NET फोरम - नेट 1.1 सी # forबनामforeach

[संपादित करें]

इसके पठनीय पहलू के अलावा, मैं वास्तव में तथ्यों और आंकड़ों में दिलचस्पी रखता हूं। ऐसे अनुप्रयोग हैं जहां अंतिम अनुकूलन प्रदर्शन अनुकूलन निचली बात करते हैं।


3
अंतर अभी भी मौजूद है। विशेष रूप से आर्गेजा केवल फॉर्च के तहत तेज होना चाहिए, लेकिन बाकी सभी चीजों के लिए, सादे लूप तेज होते हैं। बेशक, ज्यादातर समय, इससे कोई फर्क नहीं पड़ेगा, और निश्चित रूप से, एक चतुर जेआईटी संकलक सिद्धांत में अंतर को खत्म कर सकता है।
जलफ

3
संदर्भ के बिना, मैं नहीं जान सकता कि आप क्या कर रहे हैं, लेकिन क्या होता है जब आप आंशिक रूप से भरे हुए सरणी में आते हैं?
क्रिस कुडमोर

6
वैसे, 2 मिलियन हिट / महीना कुछ भी डरावना नहीं है। यह औसतन प्रति सेकंड एक हिट से कम है।
मेहरदाद आफश्री

37
महत्वपूर्ण नोट : यह प्रश्न कल C # के foreachबजाय उपयोग करने के लिए मजबूर किए जाने के बारे में पूरी तरह से असंबंधित प्रश्न के साथ विलय हो गया for। यदि आप यहां ऐसे उत्तर देखते हैं जो बिल्कुल भी समझ में नहीं आते हैं, इसीलिए। मध्यस्थ को दोषी ठहराएंगे, न कि बेबाक जवाबों को।
TED

7
@ ओह, मैं सोच रहा था कि सभी "आपका बॉस एक बेवकूफ है" टिप्पणी कहाँ से आ रही है, धन्यवाद
गैसपा79

जवाबों:


350

पैट्रिक स्मैकिया ने पिछले महीने इस बारे में ब्लॉग किया , जिसमें निम्नलिखित निष्कर्ष दिए गए हैं:

  • सूची पर छोरों के लिए सूची पर फॉर्च्यून छोरों की तुलना में 2 गुना अधिक सस्ता है।
  • सरणी पर लूपिंग सूची पर लूपिंग की तुलना में लगभग 2 गुना सस्ता है।
  • परिणामस्वरूप, फॉरेक्स का उपयोग करते हुए सूची पर लूपिंग की तुलना में सरणी का लूपिंग 5 गुना सस्ता है (जो मुझे विश्वास है, कि हम सभी करते हैं)।

130
हालांकि, कभी नहीं भूलना चाहिए: "समयपूर्व अनुकूलन सभी बुराई की जड़ है।"
ओरंग

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

47
@devinb, "for" का उपयोग करना "foreach" का उपयोग करने की तुलना में कठिन है क्योंकि यह कोड जोड़ता है, एक अन्य चर, एक शर्त जिसे आपको जांचने की आवश्यकता है, आदि। आपने "foreach" लूप में कितनी बार ऑफ-वन त्रुटि देखी है ?
tster

35
@Hardwareguy, मुझे देखने दो अगर मुझे यह सीधा मिला। एक सूची के माध्यम से लूप में 5 गुना अधिक समय लगता है foreach, क्योंकि यह एक सरणी के माध्यम से लूप करता है for, और आप उस तुच्छ को बुला रहे हैं? इस तरह का प्रदर्शन अंतर आपके आवेदन के लिए मायने रख सकता है, और यह नहीं हो सकता है, लेकिन मैं इसे सिर्फ हाथ से खारिज नहीं करूंगा।
रॉबर्ट हार्वे

44
ब्लॉग पोस्ट के माध्यम से पढ़ना ऐसा लगता है कि परीक्षण डिबग में चलाए गए थे और रिलीज नहीं हुए ताकि एक कारक हो। इसके अतिरिक्त अंतर केवल लूप ओवरहेड के लिए है। यह लूप के शरीर को निष्पादित करने के समय को प्रभावित नहीं करता है जो कि ज्यादातर मामलों में सूची के अगले तत्व को स्थानांतरित करने में लगने वाले समय की तुलना में अधिक लंबा होता है। यह जानने के लिए अच्छी जानकारी है कि आपने कब पहचान की है कि स्पष्ट रूप से एक समस्या है और आपने विशेष रूप से अपने ऐप में अंतर को मापा है और ध्यान देने योग्य सुधार है, लेकिन निश्चित रूप से सभी को हटाने के लिए सामान्य सलाह नहीं है foreach
डेवि 8

164

सबसे पहले, दिमित्री (अब हटाए गए) जवाब के लिए एक जवाबी दावा । सरणियों के लिए, C # संकलक काफी हद तक समान कोड का उत्सर्जन करता है foreachक्योंकि यह एक समान forलूप के लिए होता है । यह बताता है कि इस बेंचमार्क के लिए, परिणाम मूल रूप से समान क्यों हैं:

using System;
using System.Diagnostics;
using System.Linq;

class Test
{
    const int Size = 1000000;
    const int Iterations = 10000;

    static void Main()
    {
        double[] data = new double[Size];
        Random rng = new Random();
        for (int i=0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }

        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j=0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds);
    }
}

परिणाम:

For loop: 16638
Foreach loop: 16529

अगला, सत्यापन के बारे में कि ग्रेग की बात संग्रह प्रकार के लिए महत्वपूर्ण है - List<double>ऊपर में सरणी को बदल दें , और आपको मौलिक रूप से अलग-अलग परिणाम मिलते हैं। न केवल यह सामान्य रूप से काफी धीमा है, लेकिन सूचकांक द्वारा पहुंचने की तुलना में फोरच काफी धीमा हो जाता है। यह कहने के बाद कि, मैं अभी भी लगभग हमेशा लूप के लिए फॉरचेक को प्राथमिकता देता हूँ जहाँ यह कोड को सरल बनाता है - क्योंकि पठनीयता लगभग हमेशा महत्वपूर्ण होती है, जबकि माइक्रो-ऑप्टिमाइज़ेशन शायद ही कभी होता है।


"सरणी को ऊपर में एक सूची <डबल> में बदलें, और आपको मौलिक रूप से अलग-अलग परिणाम मिलते हैं" बहुत दिलचस्प है, मैंने इसके बारे में नहीं सोचा था
जॉन्क

5
मेरे परीक्षणों और अन्य लोगों के बेंचमार्क के बीच परिणामों में अजीब अंतर को देखते हुए, मुझे लगता है कि यह एक ब्लॉग पोस्ट को मेरिट करने जा रहा है ...
जॉन स्कीट

1
जो आप लगभग हमेशा सरणियों के बीच पसंद करते हैं और List<T>? क्या उस मामले में भी पठनीयता ट्रम्प माइक्रो-ऑप्टिमाइज़ेशन है?
जॉनबी

12
@ जॉन: यूप - मैं लगभग हमेशा List<T>सरणियों पर प्राथमिकता देता हूं । अपवाद हैं char[]और byte[]जो सामान्य संग्रह के बजाय डेटा के "विखंडू" के रूप में अधिक बार व्यवहार किए जाते हैं।
जॉन स्कीट

कमाल है, मैं अपनी मशीन पर और भी आक्रामक अंतर पा रहा हूं, साधारण सरणियों पर फॉर्च्यूनर के पक्ष में लगभग 10%। मैं बेतहाशा अनुमान लगा रहा हूं कि इस घबराहट से उपजी अतिरिक्त चर, बाउंड चेक आदि के बारे में चिंता करने की ज़रूरत नहीं है, अगर किसी को इसकी गहरी व्याख्या है तो यह बहुत दिलचस्प होगा।
तामीर दानीली

162

foreachछोरों की तुलना में अधिक विशिष्ट उद्देश्य को प्रदर्शित forछोरों

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

इसका दूसरा फायदा foreachयह है कि यह किसी भी तरह से काम करता है IEnumerable, जहां forकेवल उसी चीज का अर्थ होता है IList, जहां प्रत्येक तत्व का वास्तव में एक इंडेक्स होता है।

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

जहाँ तक मुझे पता है, कोई महत्वपूर्ण प्रदर्शन निहितार्थ नहीं हैं। भविष्य में कुछ चरणों में foreachकई कोर पर चलने के लिए कोड का अनुकूलन करना आसान हो सकता है , लेकिन अभी इसके बारे में चिंता करने की कोई बात नहीं है।


23
ctford: नहीं, यह नहीं है। संकलक निश्चित रूप से तत्वों को पुनः व्यवस्थित नहीं कर सकता है foreachforeachकार्यात्मक प्रोग्रामिंग से संबंधित नहीं है। यह पूरी तरह से प्रोग्रामिंग का एक अनिवार्य प्रतिमान है। आप TPL और PLINQ में होने वाली चीजों को गलत तरीके से देख रहे हैं foreach
मेहरदाद अफश्री

13
@BlueTrin: यह निश्चित रूप से आदेश की गारंटी देता है (C # कल्पना खंड 8.8.4 औपचारिक foreachरूप से whileलूप के बराबर परिभाषित करता है )। मुझे लगता है कि मुझे पता है कि @ctford का जिक्र है। टास्क समानांतर लाइब्रेरी अंतर्निहित संग्रह को एक मनमाना क्रम में तत्वों को प्रदान करने की अनुमति देती है ( .AsParallelएक गणना पर कॉल करके )। foreachयहां कुछ भी नहीं किया जाता है और लूप के शरीर को एक ही धागे पर निष्पादित किया जाता है । केवल एक चीज जो समानांतर है वह अनुक्रम की पीढ़ी है।
मेहरदाद अफश्री

6
Enumerable.Select में एक अधिभार होता है जो आपको आइटम के सूचकांक को प्राप्त करने देता है, इसलिए यहां तक ​​कि एक सूचकांक की आवश्यकता के लिए उपयोग करना अनिवार्य नहीं है। Msdn.microsoft.com/en-us/library/bb534869.aspx
TrueWill

5
फॉरएच पठनीयता और बचत टाइपिंग के लिए आसान है। लागत मायने रखती है, हालांकि; दस्तावेज़ डिज़ाइनर UI में 2 या 3-छोरों को बदलना जो मैंने बनाया था, (प्रत्येक obj के लिए सूची में) से (i = 0 से list.count-1 के लिए) प्रति सेकंड 2-3 सेकंड से प्रतिक्रिया समय कम कर दिया। एक छोटे से दस्तावेज़ पर प्रति सेकंड 5 सेकंड कुछ सौ वस्तुओं के माध्यम से लूपिंग। अब विशाल दस्तावेज़ों के लिए, सभी को लूप करने के लिए समय में कोई वृद्धि नहीं हुई है। मुझे नहीं पता कि यह कैसे हुआ। मुझे क्या पता है कि विकल्प केवल वस्तुओं का एक सबसेट लूप करने के लिए एक जटिल योजना थी। मैं किसी भी दिन 5 मिनट का बदलाव लूंगा! - नहीं सूक्ष्म अनुकूलन।
FastAl

5
@FastAl सामान्य सूचियों के बीच foreachऔर forप्रदर्शन का अंतर लाखों वस्तुओं पर पुनरावृत्ति के लिए एक सेकंड का अंतर है, इसलिए आपका मुद्दा निश्चित रूप से सीधे तौर पर फॉर्च्यूनर प्रदर्शन से संबंधित नहीं था, कम से कम कुछ सौ वस्तुओं के लिए नहीं। जो भी सूची आप उपयोग कर रहे थे, उसमें टूटी हुई एन्यूमरेटर कार्यान्वयन की तरह लगता है।
माइक मैरीनोव्स्की

53

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

स्टॉपवॉच क्लास का उपयोग करें और सटीकता के लिए कुछ मिलियन बार दोहराएं। (यह लूप के बिना कठिन हो सकता है):

using System.Diagnostics;
//...
Stopwatch sw = new Stopwatch()
sw.Start()
for(int i = 0; i < 1000000;i ++)
{
    //do whatever it is you need to time
}
sw.Stop();
//print out sw.ElapsedMilliseconds

फिंगर्स ने इस शो के परिणामों को पार कर लिया है कि यह अंतर नगण्य है, और हो सकता है कि आप जो भी परिणाम सबसे अधिक रखरखाव कोड में कर सकते हैं


13
लेकिन आप के लिए और foreach के प्रदर्शन की तुलना नहीं कर सकते। उनका उपयोग विभिन्न परिस्थितियों में किया जाना चाहिए।
माइकल क्रेलिन -

7
मैं आपसे सहमत हूँ माइकल, आपको यह नहीं चुनना चाहिए कि प्रदर्शन के आधार पर किसका उपयोग करना चाहिए - आपको वह चुनना चाहिए जो सबसे अधिक समझ में आता है! लेकिन अगर आपका बॉस कहता है कि "फॉरचेन की तुलना में धीमा होने के कारण उपयोग न करें" तो यह उसे समझाने का एकमात्र तरीका है कि अंतर नगण्य है
रोब फोंसेका-एनसोर

"(यह लूप के बिना कठिन हो सकता है)" या आप थोड़ी देर के लूप का उपयोग कर सकते हैं।
२२:०२ पर जॉन्सकेब

49

यह हमेशा पास रहेगा। एक सरणी के लिए, कभी-कभी for थोड़ा तेज होता है, लेकिन foreachअधिक अभिव्यंजक होता है, और LINQ प्रदान करता है, आदि सामान्य रूप से, साथ रहें foreach

इसके अतिरिक्त, foreachकुछ परिदृश्यों में अनुकूलित किया जा सकता है। उदाहरण के लिए, एक लिंक्ड सूची इंडेक्सर द्वारा भयानक हो सकती है, लेकिन इसके द्वारा त्वरित हो सकती है foreach। वास्तव में, मानक LinkedList<T>भी इस कारण के लिए एक अनुक्रमणिका प्रदान नहीं करता है।


तो क्या आप कह रहे हैं कि इससे LinkedList<T>अधिक दुबला है List<T>? और अगर मैं हमेशा foreach(इसके बजाय for) का उपयोग करने जा रहा हूं, तो मैं उपयोग करना बेहतर हूं LinkedList<T>?
जॉनबी

2
@ जॉन - दुबला नहीं; बिल्कुल अलग। उदाहरण के लिए, एक लिंक की गई सूची में प्रत्येक नोड में अतिरिक्त संदर्भ होते हैं जो एक फ्लैट सरणी (जो भी अंडरपिन List<T>) के लिए आवश्यक नहीं हैं । यह अधिक है कि यह सम्मिलित करना / हटाना सस्ता है ।
मार्क ग्रेवेल

36

मेरा अनुमान है कि 99% मामलों में यह महत्वपूर्ण नहीं होगा, इसलिए आप सबसे उपयुक्त के बजाय तेजी का चयन क्यों करेंगे (जैसा कि समझने / बनाए रखने में सबसे आसान है)?


6
@klew, यदि आप वास्तव में अपना कोड प्रोफाइल करते हैं, तो आपको यह अनुमान नहीं लगाना होगा कि 20% को जितनी जल्दी हो सके उतनी तेजी से होने की आवश्यकता है। आपको शायद यह भी पता चल जाएगा कि वास्तविक संख्या में छोरों को तेज होने की आवश्यकता बहुत कम है। इसके अलावा, क्या आप वास्तव में कह रहे हैं कि लूपिंग का कार्य वह है जहाँ आप अपना समय व्यतीत करते हैं, क्योंकि आप वास्तव में उस पाश में क्या करते हैं?
tster

32

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

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


32

इसके बहुत अच्छे कारण हैं foreachछोरों पर forछोरों पसंद हैं । यदि आप एक का उपयोग कर सकते हैंforeach लूप का , तो आपका बॉस सही है जो आपको चाहिए।

हालांकि, प्रत्येक पुनरावृत्ति क्रम में एक-एक करके सूची से नहीं गुजर रही है। अगर वह इसके लिए मना कर रहा है, हां यह गलत है।

अगर मैं तुम होते, तो मैं क्या करता , तुम्हारी सारी स्वाभाविकता को छोरों की पुनरावृत्ति में बदल दूंगा । वह उसे सिखाएगा, और यह आपके लिए एक अच्छा मानसिक व्यायाम भी है।


प्रदर्शन-वार forछोरों और foreachछोरों की तुलना कैसे की जाती है ?
जॉनबी

निर्भर करता है। यदि आप पूंछ-पुनरावृत्ति का उपयोग करते हैं और आपका संकलक सूचना के लिए पर्याप्त स्मार्ट है, तो यह समान हो सकता है। OTOH: यदि ऐसा नहीं होता है और आप कुछ बेवकूफी करते हैं जैसे कि बहुत सी असमानता (अपरिवर्तनशील) डेटा को मापदंडों के रूप में पास करते हैं या स्टैक पर बड़ी संरचनाओं को स्थानीय लोगों के रूप में घोषित करते हैं, तो यह वास्तव में धीमा हो सकता है (या रैम से बाहर भी दौड़ सकता है)।
TED

आह। मैं देख रहा हूं कि आपने ऐसा क्यों पूछा। यह उत्तर बिलकुल भिन्न प्रश्न पर गया। कुछ बिज़ारे कारण के लिए जोनाथन सैम्पसन ने कल दोनों को मिला दिया। वह वास्तव में ऐसा नहीं करना चाहिए था। मर्ज किए गए जवाबों का यहां कोई मतलब नहीं होगा।
TED

18

टेकएड 2005 पर जेफरी रिक्टर:

"मैं वर्षों से सीखता आया हूं कि C # संकलक मूल रूप से मेरे लिए एक झूठा है।" .. "यह कई चीजों के बारे में है।" .. "जैसे जब आप एक फॉर्च्यूड लूप करते हैं ..." .. "... यह कोड की एक छोटी सी लाइन होती है जिसे आप लिखते हैं, लेकिन सी # कंपाइलर ऐसा करने के लिए बाहर थूकता है कि यह अभूतपूर्व है। यह बाहर डालता है। कोशिश करें / अंत में वहां ब्लॉक करें, अंत में इसे ब्लॉक करें यह आपके वैरिएबल को एक आईडीसॉफ़र इंटरफ़ेस में डाल देता है, और यदि कास्ट सक्सेज़ करता है तो इसे डिस्पोज़ मेथड कहता है, लूप के अंदर यह करंट प्रॉपर्टी और मूवनेट विधि को लूप के अंदर बार-बार कॉल करता है। ऑब्जेक्ट्स को कवर के नीचे बनाया जा रहा है। बहुत से लोग फॉर्च्यूनर का उपयोग करते हैं क्योंकि यह बहुत आसान कोडिंग है, जो करना बहुत आसान है .. ".." प्रदर्शन के मामले में फॉर्च्यूनर बहुत अच्छा नहीं है,

ऑन-डिमांड वेबकास्ट: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en_US&CountryCode=US


12

यह मज़ाकीय है। फॉर-लूप, प्रदर्शन-वार या अन्य पर प्रतिबंध लगाने के लिए कोई बाध्यकारी कारण नहीं है।

एक प्रदर्शन बेंचमार्क और अन्य तर्कों के लिए जॉन स्कीट का ब्लॉग देखें ।


2
अद्यतित लिंक: codeblog.jonskeet.uk/2009/01/29/…
मैट

लूप का निर्माण जो तेजी से होता है, वह इस बात पर निर्भर करता है कि आपको किस चीज पर अधिक चलना चाहिए। एक अन्य ब्लॉग जो कई प्रकार के ऑब्जेक्ट्स , जैसे कि DataRows और कस्टम ऑब्जेक्ट्स पर कई पुनरावृत्तियों को बेंचमार्क करता है । इसमें लूप कंस्ट्रक्शन का प्रदर्शन भी शामिल है और न केवल फॉर और फॉरच लूपिंग कंस्ट्रक्शन।
फ्री कोडर 24

11

ऐसे मामलों में जहां आप वस्तुओं के संग्रह के साथ काम करते हैं, foreachबेहतर है, लेकिन अगर आप संख्या बढ़ाते हैं, तोfor लूप बेहतर होता है।

ध्यान दें कि अंतिम स्थिति में, आप कुछ ऐसा कर सकते हैं:

foreach (int i in Enumerable.Range(1, 10))...

लेकिन यह निश्चित रूप से बेहतर प्रदर्शन नहीं करता है, वास्तव में इसकी तुलना में खराब प्रदर्शन है for


"बेहतर" बहस करने योग्य है: यह धीमा है और dnspy ​​डीबगर एक C # फ़ॉरेस्ट में नहीं टूटेगा (हालांकि VS2017 डीबगर होगा)। कभी-कभी अधिक पढ़ने योग्य लेकिन यदि आप इसके बिना भाषाओं का समर्थन करते हैं, तो यह कष्टप्रद हो सकता है।
Zeek2

10

यह आपको बचाना चाहिए:

public IEnumerator<int> For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

उपयोग:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

अधिक से अधिक जीत के लिए, आप तीन प्रतिनिधियों को मापदंडों के रूप में ले सकते हैं।


1
एक छोटा सा अंतर यह है कि एक forलूप आमतौर पर सीमा के अंत (जैसे 0 <= i < 10) को बाहर करने के लिए लिखा जाता है । Parallel.Forयह भी एक आम forलूप के साथ आसानी से विनिमेय रखने के लिए करता है ।
Groo

9

आप इसके बारे में Deep .NET - part 1 Iteration में पढ़ सकते हैं

यह .NET स्रोत कोड से परिणाम (पहले आरंभिक के बिना) को कवर करता है।

उदाहरण के लिए - फॉरेस्ट लूप के साथ ऐरे इटरेशन: यहां छवि विवरण दर्ज करें

और - फोर्क लूप के साथ सूची पुनरावृत्ति: यहां छवि विवरण दर्ज करें

और अंतिम परिणाम: यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें


8

जब आप सरणियों, सूचियों, आदि जैसी सामान्य संरचनाओं से गुजर रहे हों, तो a for- और a foreach-loop में गति के अंतर छोटे होते हैंLINQ कलेक्शन पर क्वेरी लगभग हमेशा थोड़ा धीमा होता है, हालांकि यह लिखने के लिए अच्छा है! जैसा कि अन्य पोस्टरों ने कहा, अतिरिक्त प्रदर्शन के एक मिलीसेकंड के बजाय अभिव्यक्ति के लिए जाएं।

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

foreachलूप के साथ एक अन्य महत्वपूर्ण लाभ यह है कि यदि आपका संग्रह कार्यान्वयन ( उदाहरण के arrayलिए एक List<int>उदाहरण से) बदल जाता है तो आपके foreachलूप को किसी भी कोड परिवर्तन की आवश्यकता नहीं होगी:

foreach (int i in myCollection)

उपरोक्त वही है जो आपके संग्रह का प्रकार क्या है कोई फर्क नहीं पड़ता, जबकि आपके forलूप में, निम्न का निर्माण नहीं होगा यदि आप ए myCollectionसे बदल गए हैं :arrayList

for (int i = 0; i < myCollection.Length, i++)

7

"क्या कोई तर्क है जिसकी मदद से मैं उसे समझाने में मदद कर सकता हूं कि लूप उपयोग के लिए स्वीकार्य है?"

नहीं, यदि आपका बॉस आपको बता रहा है कि प्रोग्रामिंग भाषा किस स्तर का उपयोग करती है, तो आप वास्तव में कुछ भी नहीं कह सकते हैं। माफ़ करना।


7

यह संभवत: संग्रह के प्रकार पर निर्भर करता है जिसे आप गणना कर रहे हैं और इसके अनुक्रमणिका का कार्यान्वयन। सामान्य तौर पर, उपयोग foreachकरना बेहतर दृष्टिकोण होने की संभावना है।

इसके अलावा, यह किसी भी के साथ काम करेंगे IEnumerable- न केवल इंडेक्सर्स के साथ चीजें।


7

इसके दो समान उत्तर हैं जो "सबसे तेज़" प्रश्न हैं:

1) यदि आप माप नहीं करते हैं, तो आप नहीं जानते।

2) (क्योंकि ...) यह निर्भर करता है।

यह इस बात पर निर्भर करता है कि "MoveNext ()" विधि कितनी महंगी है, IEnumerable के प्रकार (या प्रकार) के लिए "यह [int index]" विधि कितनी महंगी है, के सापेक्ष आप इससे अधिक पुनरावृत्त होंगे।

"Foreach" कीवर्ड संचालन की एक श्रृंखला के लिए शॉर्टहैंड है - यह IEEumerable पर एक बार GetEnumerator () कहता है, इसे MoveNext () प्रति बार एक बार कॉल करता है, यह कुछ प्रकार की जाँच करता है, और इसी तरह। प्रदर्शन मापों को प्रभावित करने की सबसे अधिक संभावना मूवएन टेक्स्ट () की लागत है क्योंकि यह ओ (एन) बार प्राप्त होता है। शायद यह सस्ता है, लेकिन शायद यह नहीं है।

"फॉर" कीवर्ड अधिक अनुमानित है, लेकिन अधिकांश "अंदर" के लिए "लूप्स" आपको "संग्रह [इंडेक्स]" जैसा कुछ मिलेगा। यह एक साधारण सरणी इंडेक्सिंग ऑपरेशन की तरह दिखता है, लेकिन यह वास्तव में एक विधि कॉल है, जिसकी लागत पूरी तरह से उस संग्रह की प्रकृति पर निर्भर करती है जो आप पर निर्भर हैं। शायद यह सस्ता है, लेकिन शायद यह नहीं है।

यदि संग्रह की अंतर्निहित संरचना अनिवार्य रूप से एक लिंक की गई सूची है, तो MoveNext गंदगी-सस्ता है, लेकिन अनुक्रमणिका में O (N) लागत हो सकती है, जिससे "O" (N * N) के लिए "सही लागत" बनती है।


6

प्रत्येक भाषा निर्माण में उपयोग के लिए उपयुक्त समय और स्थान होता है। वहाँ एक कारण है C # भाषा में चार अलग-अलग चलना कथन हैं - प्रत्येक एक विशिष्ट उद्देश्य के लिए है, और इसका एक उपयुक्त उपयोग है।

मैं आपके बॉस के साथ बैठने की सलाह देता हूं और तर्कसंगत रूप से समझाने की कोशिश करता हूं कि एक forलूप का उद्देश्य क्यों है । ऐसे समय होते हैं जब एक forपुनरावृत्ति ब्लॉक अधिक स्पष्ट रूप से एक foreachपुनरावृत्ति की तुलना में एल्गोरिथ्म का वर्णन करता है । जब यह सच है, तो उनका उपयोग करना उचित है।

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

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


5

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


5

क्या वास्तव में बिंदु के अलावा forतेजी है foreach। मुझे गंभीरता से संदेह है कि एक को चुनने पर आपके प्रदर्शन पर महत्वपूर्ण प्रभाव पड़ेगा।

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

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


अगर मैं जिन परियोजनाओं पर काम करता हूं, उनमें माइक्रो ऑप्टिमाइज़ेशन के लिए मुझे केवल एक ही तरह के अनुकूलन की आवश्यकता होती है, मैं एक खुश टूरिस्ट हूं। अफसोस की बात है, यह कभी नहीं होता है।
यनिक मटन

2
forसे थोड़ा तेज है foreach। मुझे इस कथन पर गंभीर आपत्ति होगी। यह पूरी तरह से अंतर्निहित संग्रह पर निर्भर करता है। यदि एक लिंक की गई सूची वर्ग एक पूर्णांक पैरामीटर के साथ एक अनुक्रमणिका प्रदान करता है, तो मैं forओ (एन ^ 2) पर एक लूप का उपयोग करने की उम्मीद करूंगा, जबकि foreachओ (एन) होने की उम्मीद है।
मेहरदाद आफश्री

@ मिरहद: वास्तव में यह एक अच्छा बिंदु है। मैं सिर्फ एक सूची (यानी सरणी) को अनुक्रमित करने के नियमित मामले के बारे में सोच रहा था। मैं उसे दर्शाने के लिए फिर से तैयार करूँगा। धन्यवाद।
ब्रायन रासमुसेन

@ मेहरदाद अफशरी: पूर्णांक द्वारा एक संग्रह को अनुक्रमित करना, उस पर गणना करने की तुलना में बहुत धीमा हो सकता है। लेकिन आप वास्तव में उपयोग करने की तुलना कर रहे हैं for और एक अनुक्रमणिका लुकअप foreachद्वारा स्वयं का उपयोग कर रहे हैं। मुझे लगता है कि @ ब्रायन रासमुसेन का जवाब सही है कि, एक संग्रह के साथ किसी भी उपयोग से अलग, forहमेशा की तुलना में थोड़ा तेज होगा foreach। हालाँकि, forप्लस संग्रह देखने की क्षमता हमेशा foreachअपने आप से धीमी होगी ।
डैनियल प्रेडेन

@ डैनियल: या तो आपके पास एक सादा सरणी है, जिसके लिए दोनों समान कोड उत्पन्न करेंगे, या जब आप forस्टेटमेंट का उपयोग करते हैं तो एक इंडेक्सर शामिल होता है । forपूर्णांक नियंत्रण चर के साथ सादा लूप तुलनीय नहीं है foreach, इसलिए यह बाहर है। मैं समझता हूं कि @ ब्रायन का क्या अर्थ है और यह सही है जैसा कि आप कहते हैं लेकिन उत्तर भ्रामक हो सकता है। पुन: अपने अंतिम बिंदु: नहीं, वास्तव में, forसे अधिक List<T>अभी भी तेजी से है foreach
मेहरदाद आफश्री

4

दोनों लगभग एक ही तरह से चलेंगे। दोनों का उपयोग करने के लिए कुछ कोड लिखें, फिर उसे आईएल दिखाएं। यह तुलनीय संगणना दिखाना चाहिए, जिसका अर्थ है प्रदर्शन में कोई अंतर नहीं।


संकलक सरणियों / ILists आदि पर उपयोग किए जाने वाले फोरच लूप को पहचानता है और उन्हें लूप के लिए बदलता है।
कैलम रोजर्स

3
उसे अचिंत्य प्रमाण की पंक्तियाँ दिखाएँ कि यह ठीक है और उसका प्रमाण माँगें कि यह ठीक नहीं है।
cjk

3

के लिए लागू करने के लिए और अधिक सरल तर्क है इसलिए यह फॉर्च्यूनर से तेज है।


3

जब तक आप एक विशिष्ट गति अनुकूलन प्रक्रिया में न हों, मैं कहूँगा कि जो भी विधि कोड को पढ़ने और बनाए रखने के लिए सबसे आसान तरीके का उपयोग करता है।

यदि एक पुनरावृत्ति पहले से ही सेटअप है, जैसे संग्रह कक्षाओं में से एक के साथ, तो फ़ॉरच एक अच्छा आसान विकल्प है। और अगर यह एक पूर्णांक श्रेणी है जो आप पुनरावृत्त कर रहे हैं, तो संभवतः क्लीनर है।



3

ज्यादातर मामलों में वास्तव में कोई अंतर नहीं है।

आमतौर पर आपको हमेशा एक स्पष्ट संख्यात्मक सूचकांक नहीं होने पर फॉर्च्यूनर का उपयोग करना पड़ता है, और आपको हमेशा तब उपयोग करना होता है जब आपके पास वास्तव में चलने योग्य संग्रह नहीं होता है (जैसे ऊपरी त्रिकोण में दो आयामी सरणी ग्रिड पर पुनरावृत्ति करना) । कुछ मामले हैं जहां आपके पास एक विकल्प है।

कोई यह तर्क दे सकता है कि कोड में मैजिक नंबर दिखाई देने लगे तो लूप्स को बनाए रखना थोड़ा मुश्किल हो सकता है। आपको लूप का उपयोग करने में सक्षम नहीं होने पर नाराज होना चाहिए और एक संग्रह का निर्माण करना होगा या लैंबडा का उपयोग करने के बजाय एक सबकोलिलेशन बनाना होगा क्योंकि लूप पर प्रतिबंध लगाया गया है।


3

यह लूप के लिए किसी चीज के उपयोग को पूरी तरह से मना करने के लिए थोड़ा अजीब लगता है।

यहाँ एक दिलचस्प लेख है जिसमें दो छोरों के बीच बहुत सारे प्रदर्शन अंतर हैं।

मैं व्यक्तिगत रूप से कहूंगा कि मुझे लूप के लिए थोड़ा अधिक पठनीय लगता है, लेकिन आपको हाथ में काम के लिए सबसे अच्छा उपयोग करना चाहिए और फॉरेस्ट लूप को शामिल करने के लिए अतिरिक्त लंबा कोड नहीं लिखना होगा यदि लूप अधिक उपयुक्त है।


आवश्यक उद्धरण उस लेख को बनाते हैं जो आप से लिंक करते हैं: "... यदि आप उच्च प्रदर्शन कोड लिखने की योजना बना रहे हैं जो संग्रह के लिए नहीं है, तो लूप के लिए उपयोग करें। यहां तक ​​कि संग्रह के लिए, उपयोग करते समय फ़ॉरच देखने में आसान हो सकता है, लेकिन यह उतना कुशल नहीं है।"
NickFitz

3

मुझे वह foreachलूप मिला जो List तेजी से घूमता था । मेरे परीक्षा परिणाम नीचे देखें। नीचे दिए गए कोड में मैंने समय को मापने के लिए array100, 10000 और 100000 के आकार का अलग-अलग उपयोग किया है forऔर foreachलूप का उपयोग किया है।

यहां छवि विवरण दर्ज करें

private static void MeasureTime()
    {
        var array = new int[10000];
        var list = array.ToList();
        Console.WriteLine("Array size: {0}", array.Length);

        Console.WriteLine("Array For loop ......");
        var stopWatch = Stopwatch.StartNew();
        for (int i = 0; i < array.Length; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("Array Foreach loop ......");
        var stopWatch1 = Stopwatch.StartNew();
        foreach (var item in array)
        {
            Thread.Sleep(1);
        }
        stopWatch1.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List For loop ......");
        var stopWatch2 = Stopwatch.StartNew();
        for (int i = 0; i < list.Count; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch2.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List Foreach loop ......");
        var stopWatch3 = Stopwatch.StartNew();
        foreach (var item in list)
        {
            Thread.Sleep(1);
        }
        stopWatch3.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds);
    }

UPDATED

@Jgauffin सुझाव के बाद मैंने @johnskeet कोड का उपयोग किया और पाया कि forलूप arrayनिम्नलिखित के साथ अधिक तेज़ है,

  • सरणी के साथ फॉर्च लूप।
  • सूची के साथ लूप के लिए।
  • सूची के साथ फ़ॉरच लूप।

नीचे मेरे परीक्षा परिणाम और कोड देखें,

यहां छवि विवरण दर्ज करें

private static void MeasureNewTime()
    {
        var data = new double[Size];
        var rng = new Random();
        for (int i = 0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }
        Console.WriteLine("Lenght of array: {0}", data.Length);
        Console.WriteLine("No. of iteration: {0}", Iterations);
        Console.WriteLine(" ");
        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with Array: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (var i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with Array: {0}", sw.ElapsedMilliseconds);
        Console.WriteLine(" ");

        var dataList = data.ToList();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < dataList.Count; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in dataList)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds);
    }

3
यह बहुत खराब परीक्षा है। क) आप एक निर्णायक उत्तर प्राप्त करने के लिए बहुत कम पुनरावृत्तियों करते हैं) वह थ्रेड। सो वास्तव में एक मिलीसेकंड प्रतीक्षा नहीं करेगा। उसी विधि का उपयोग करें जैसा कि जॉन स्कीट ने अपने उत्तर में किया था।
jgauffin 5

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

3

आप वास्तव में उसके सिर के साथ पेंच कर सकते हैं और इसके बजाय एक IQueryable .foreach बंद करने के लिए जा सकते हैं:

myList.ForEach(c => Console.WriteLine(c.ToString());

3
मैं आपकी लाइन को कोड के साथ बदल दूंगा myList.ForEach(Console.WriteLine)
मेहरदाद अफश्री

2

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

मुझे लगता है कि उत्तर इस बात पर निर्भर करता है कि जिस संग्रह को आप एक्सेस करने का प्रयास कर रहे हैं, उसमें एक तेज इंडेक्सर एक्सेस कार्यान्वयन या एक तेज IEnumerator एक्सेस कार्यान्वयन है। चूंकि IEnumerator अक्सर अनुक्रमणिका का उपयोग करता है और बस वर्तमान अनुक्रमणिका स्थिति की एक प्रति रखता है, इसलिए मैं गणनाकर्ता की पहुँच को कम से कम धीमे या धीमे प्रत्यक्ष अनुक्रमणिका पहुँच की अपेक्षा करता हूँ, लेकिन बहुत अधिक नहीं।

बेशक यह जवाब संकलक लागू हो सकता है किसी भी अनुकूलन के लिए खाता नहीं है।


C # संकलक बहुत कम अनुकूलन करता है, यह वास्तव में JITter तक छोड़ देता है।
ljs

खैर, JITTER एक संकलक है ... सही है?
जोहान्सह

2

ध्यान रखें कि फॉर-लूप और फ़ॉरच-लूप हमेशा समतुल्य नहीं होते हैं। यदि सूची में बदलाव होता है तो सूची एनुमेरिटर्स एक अपवाद को फेंक देंगे, लेकिन आपको हमेशा लूप के लिए एक सामान्य चेतावनी नहीं मिलेगी। यदि सूची गलत समय पर बदलती है तो आपको एक अलग अपवाद भी मिल सकता है।


अगर सूची आपके नीचे से बदल रही है, तो आप एनुमर पर भरोसा नहीं कर सकते कि आपको यह बताने के लिए एक फ़ॉरच लूप का सहारा लेना चाहिए। यह आपके लिए मान वापस करने के बाद फिर से जांच करने वाला नहीं है, जिसके परिणामस्वरूप एक दौड़ होती है।
हुडेटिकस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.