Database
 sql >> डेटाबेस >  >> RDS >> Database

Foreach या For – यही सवाल है

FOREACH और FOR के बीच वरीयता अंतर के बारे में चर्चा कोई नई बात नहीं है। हम सभी जानते हैं कि FOREACH धीमा है, लेकिन सभी नहीं जानते कि क्यों।

जब मैंने .NET सीखना शुरू किया, तो एक व्यक्ति ने मुझसे कहा कि FOREACH, FOR की तुलना में दो गुना धीमा है। उन्होंने बिना किसी आधार के यह बात कही। मैंने इसे हल्के में लिया।

आखिरकार, मैंने FOREACH और FOR लूप प्रदर्शन अंतर का पता लगाने का फैसला किया, और बारीकियों पर चर्चा करने के लिए इस लेख को लिखा।
आइए निम्नलिखित कोड पर एक नज़र डालें:

foreach (var item in Enumerable.Range(0, 128))
{
  Console.WriteLine(item);
}

FOREACH एक सिंटेक्स शुगर है। इस विशेष मामले में, कंपाइलर इसे निम्नलिखित कोड में बदल देता है:

IEnumerator<int> enumerator = Enumerable.Range(0, 128).GetEnumerator();
try
 {
   while (enumerator.MoveNext())
   {
     int item = enumerator.Current;
     Console.WriteLine(item);
   }
 }
finally
 {
  if (enumerator != null)
  {
   enumerator.Dispose();
  }
}

यह जानकर, हम इसका कारण मान सकते हैं कि FOREACH FOR की तुलना में धीमा क्यों है:

  • एक नई वस्तु बनाई जा रही है। इसे निर्माता कहा जाता है।
  • मूवनेक्स्ट विधि को प्रत्येक पुनरावृत्ति पर कहा जाता है।
  • प्रत्येक पुनरावृत्ति वर्तमान संपत्ति तक पहुंचती है।

इतना ही! हालाँकि, यह सब उतना आसान नहीं है जितना लगता है।

सौभाग्य से (या दुर्भाग्य से), सी #/सीएलआर रन टाइम पर अनुकूलन कर सकता है। पेशेवर यह है कि कोड तेजी से काम करता है। चोर - डेवलपर्स को इन अनुकूलन के बारे में पता होना चाहिए।

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

परीक्षण के तरीके

static double ArrayForWithoutOptimization(int[] array)
{
   int sum = 0;
   var watch = Stopwatch.StartNew();
   for (int i = 0; i < array.Length; i++)
     sum += array[i];
    watch.Stop();
    return watch.Elapsed.TotalMilliseconds;
}

static double ArrayForWithOptimization(int[] array)
{
   int length = array.Length;
   int sum = 0;
   var watch = Stopwatch.StartNew();
    for (int i = 0; i < length; i++)
      sum += array[i];
    watch.Stop();
     return watch.Elapsed.TotalMilliseconds;
}

static double ArrayForeach(int[] array)
{
  int sum = 0;
  var watch = Stopwatch.StartNew();
   foreach (var item in array)
    sum += item;
  watch.Stop();
  return watch.Elapsed.TotalMilliseconds;
}

static double ArrayForEach(int[] array)
{
  int sum = 0;
  var watch = Stopwatch.StartNew();
  Array.ForEach(array, i => { sum += i; });
  watch.Stop();
  return watch.Elapsed.TotalMilliseconds;
}

परीक्षण की स्थिति:

  • “ऑप्टिमाइज़ कोड” विकल्प चालू है।
  • तत्वों की संख्या 100 000 000 (सरणी और सूची दोनों में) के बराबर है।
  • पीसी विनिर्देश:Intel Core i-5 और 8 GB RAM।

सरणी

आरेख से पता चलता है कि सरणी के माध्यम से पुनरावृत्ति करते समय FOR और FOREACH समान समय व्यतीत करते हैं। और ऐसा इसलिए है क्योंकि सीएलआर अनुकूलन FOREACH को FOR में परिवर्तित करता है, और सरणी की लंबाई को अधिकतम पुनरावृत्ति सीमा के रूप में उपयोग करता है। इससे कोई फर्क नहीं पड़ता कि सरणी की लंबाई कैश की गई है या नहीं (फोर का उपयोग करते समय), परिणाम लगभग समान है।

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

Array.foreach सबसे खराब परिणाम दिखाया। इसका क्रियान्वयन काफी सरल है:

public static void ForEach<T>(T[] array, Action<T> action)
 {
  for (int index = 0; index < array.Length; ++index)
    action(array[index]);
 }

फिर यह इतना धीमा क्यों चल रहा है? यह हुड के नीचे FOR का उपयोग करता है। खैर, इसका कारण ACTION प्रतिनिधि को बुलाना है। वास्तव में, प्रत्येक पुनरावृत्ति पर एक विधि कहा जाता है, जो प्रदर्शन को कम करता है। इसके अलावा, प्रतिनिधियों को उतनी तेजी से नहीं बुलाया जाता जितना हम चाहेंगे।

सूचियां

नतीजा बिल्कुल अलग है। सूचियों को पुनरावृत्त करते समय, FOR और FOREACH अलग-अलग परिणाम दिखाते हैं। कोई अनुकूलन नहीं है। FOR (सूची की लंबाई को कैशिंग के साथ) सबसे अच्छा परिणाम दिखाता है, जबकि FOREACH 2 गुना से अधिक धीमा है। ऐसा इसलिए है क्योंकि यह हुड के तहत मूवनेक्स्ट और करंट से संबंधित है। List.ForEach के साथ-साथ Array.ForEach सबसे खराब परिणाम दिखाता है। प्रतिनिधियों को हमेशा वस्तुतः बुलाया जाता है। इस पद्धति का कार्यान्वयन इस तरह दिखता है:

public void ForEach(Action<T> action)
{
  int num = this._version;
   for (int index = 0; index < this._size && num == this._version; ++index)
     action(this._items[index]);
   if (num == this._version)
     return;
   ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}

प्रत्येक पुनरावृत्ति क्रिया प्रतिनिधि को बुलाती है। यह भी जांचता है कि सूची बदली गई है या नहीं और यदि ऐसा है, तो एक अपवाद फेंक दिया गया है।

सूची आंतरिक रूप से एक सरणी-आधारित मॉडल का उपयोग करती है और ForEach विधि पुनरावृति करने के लिए सरणी अनुक्रमणिका का उपयोग करती है, जो अनुक्रमणिका का उपयोग करने की तुलना में काफी तेज़ है।

विशिष्ट संख्या

  1. लंबाई कैशिंग और FOREACH के बिना FOR लूप, लंबाई कैशिंग के साथ FOR की तुलना में सरणियों पर थोड़ा तेज़ काम करता है।
  2. सरणी।Foreach प्रदर्शन FOR / FOREACH प्रदर्शन की तुलना में लगभग 6 गुना धीमा है।
  3. लंबाई कैशिंग के बिना फॉर लूप, सरणियों की तुलना में सूचियों पर 3 गुना धीमा काम करता है।
  4. लंबाई कैशिंग के साथ फॉर लूप, सरणियों की तुलना में सूचियों पर 2 गुना धीमा काम करता है।
  5. फ़ोरैच लूप, सरणियों की तुलना में सूचियों पर 6 गुना धीमी गति से काम करता है।

यहाँ सूचियों के लिए एक लीडर बोर्ड है:

और सरणियों के लिए:

निष्कर्ष

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

FOREACH का उपयोग करते समय कोड बेहतर दिखता है, और आधुनिक प्रोसेसर इसका उपयोग करने की अनुमति देते हैं। हालांकि, यदि आपको अपने कोडबेस को अत्यधिक अनुकूलित करने की आवश्यकता है, तो इसका उपयोग करना बेहतर है।

आपको क्या लगता है, कौन सा लूप तेजी से चलता है, FOR या FOREACH?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. वर्चुअल कॉलम और फंक्शनल इंडेक्स

  2. अपने एमएस एसक्यूएल प्रतिकृति का प्रबंधन

  3. सिंथेटिक डेटा जनरेशन

  4. समानांतर योजनाएँ कैसे शुरू होती हैं - भाग 1

  5. री-आईडी जोखिम को कम करने के लिए अप्रत्यक्ष पहचानकर्ताओं को गुमनाम करना