2013-02-15 24 views
27

बहुत संक्षिप्त प्रश्न। मेरे पास एक यादृच्छिक रूप से क्रमबद्ध बड़ी स्ट्रिंग सरणी (100K + प्रविष्टियां) है जहां मैं वांछित स्ट्रिंग का पहला मौका ढूंढना चाहता हूं। मेरे पास दो समाधान हैं।- प्रदर्शन बनाम भविष्य

पढ़ने के बाद मैं क्या अनुमान लगा सकता हूं कि 'लूप' वर्तमान में थोड़ा बेहतर प्रदर्शन करने जा रहा है (लेकिन यह मार्जिन हमेशा बदल सकता है), लेकिन मुझे linq संस्करण भी अधिक पठनीय लगता है। संतुलन पर कौन सी विधि को आम तौर पर वर्तमान सर्वोत्तम कोडिंग अभ्यास माना जाता है और क्यों?

string matchString = "dsf897sdf78"; 
int matchIndex = -1; 
for(int i=0; i<array.length; i++) 
{ 
    if(array[i]==matchString) 
    { 
     matchIndex = i; 
     break; 
    } 
} 

या

int matchIndex = array.Select((r, i) => new { value = r, index = i }) 
         .Where(t => t.value == matchString) 
         .Select(s => s.index).First(); 
+0

संबंधित: [बनाम फोरैच बनाम LINQ] (http://programmers.stackexchange.com/questions/178218/for-vs-foreach-vs-linq) – sloth

+3

मैं इस में LINQ का भी उपयोग नहीं करता मामला, क्योंकि आपको वास्तव में इंडेक्स खोजने के लिए लड़ना है - मैं 'Array.IndexOf' का उपयोग करता हूं :) – Rawling

+0

मैं किसी भी प्रदर्शन समस्या के बिना बड़े डेटाटेबल्स (100k + रिकॉर्ड्स, ~ 40 कॉलम) पर LINQ का उपयोग करता हूं। – Teejay

उत्तर

41

सबसे अच्छा अभ्यास पर निर्भर करता है कि तुम क्या जरूरत है:

  1. विकास की गति और रख-रखाव: LINQ
  2. प्रदर्शन (प्रोफ़ाइलिंग टूल के अनुसार): मैनुअल कोड

LINQ वास्तव में सभी संकेतों के साथ धीमी चीजें करता है। इसके बारे में चिंता न करें क्योंकि आपका 99% कोड अंतिम उपयोगकर्ता प्रदर्शन को प्रभावित नहीं करता है।

मैंने सी ++ के साथ शुरुआत की और वास्तव में कोड के एक टुकड़े को अनुकूलित करने का तरीका सीखा। LINQ आपके सीपीयू से अधिक लाभ प्राप्त करने के लिए उपयुक्त नहीं है। तो यदि आप किसी समस्या के लिए LINQ क्वेरी को मापते हैं तो बस इसे हटा दें। लेकिन केवल तभी।

आपके कोड नमूने के लिए मैं 3x मंदी का अनुमान लगाऊंगा। आवंटन (और बाद में जीसी!) और भेड़ के बच्चे के माध्यम से संकेत वास्तव में चोट पहुंचाते हैं।

+0

सहमत हुए। लिंक एक छोटी प्रदर्शन लागत पर आता है, लेकिन कई मामलों में यह लापरवाह है। वास्तव में, जो मुझे याद है, स्टैक ओवरव्लो के पीछे के अधिकांश कोड को लिंक –

+0

+1 का उपयोग करता है और जोड़ना चाहता है कि कोड का केवल 20% 80% समय चलता है, इसलिए यदि कोई प्रदर्शन समस्या है तो केवल बाधाओं को अनुकूलित किया जाना चाहिए –

+1

+ 1 99.9% सीधे अच्छी व्याख्या ':) ' – spajce

2

ठीक है, आपने अपने प्रश्न का उत्तर स्वयं दिया है।

यदि आप बेहतर प्रदर्शन चाहते हैं, तो For लूप के साथ जाएं, या Linq के साथ जाएं यदि आप पठनीयता चाहते हैं।

शायद समानांतर। Foreach() का उपयोग करने की संभावना को ध्यान में रखें जो लाइन लैम्ब्डा अभिव्यक्तियों से लाभान्वित होगा (इसलिए, लिंकक के करीब), और यह अधिक पढ़ने योग्य है तो पैरालाइजेशन "मैन्युअल" कर रहा है।

+1

मैंने हमेशा सोचा है कि क्यों LINQ और lambda अभिव्यक्तियों को स्वचालित रूप से अधिक पठनीय माना जाता है। कभी-कभी LINQ IMO –

+0

@LeeDale की तुलना में एक साधारण फोरच या अधिक पठनीय है। और मैं अपना जवाब जोड़ना चाहता हूं लिंकक के फ्लुएंट-स्टाइल लेआउट के बारे में, प्रश्न में, घोषणात्मक शैली नहीं। प्रयासों के लिए PLINQ ': D' – dutzu

1

मुझे नहीं लगता कि या तो सबसे अच्छा अभ्यास माना जाता है कुछ लोग LINQ को देखना पसंद करते हैं और कुछ नहीं करते हैं।

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

क्या आपने PLINQ का उपयोग करने या लूप को समानांतर में चलाने के बारे में सोचा है?

+0

+1: डी' – spajce

2

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

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

Array.IndexOf(array, matchString) 
24

थोड़ा बेहतर प्रदर्शन? एक लूप स्पष्ट रूप से बेहतर प्रदर्शन देगा!

नीचे दिए गए कोड पर विचार करें। एक विज्ञप्ति (नहीं डिबग) निर्माण के लिए अपने सिस्टम पर, यह देता है:

Found via loop at index 999999 in 00:00:00.2782047 
Found via linq at index 999999 in 00:00:02.5864703 
Loop was 9.29700432810805 times faster than linq. 

कोड जान-बूझकर की स्थापना की है ताकि आइटम नहीं मिल करने के लिए सही अंत में है। अगर यह शुरुआत में सही था, तो चीजें काफी अलग होंगी।

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main(string[] args) 
     { 
      string[] a = new string[1000000]; 

      for (int i = 0; i < a.Length; ++i) 
      { 
       a[i] = "Won't be found"; 
      } 

      string matchString = "Will be found"; 

      a[a.Length - 1] = "Will be found"; 

      const int COUNT = 100; 

      var sw = Stopwatch.StartNew(); 
      int matchIndex = -1; 

      for (int outer = 0; outer < COUNT; ++outer) 
      { 
       for (int i = 0; i < a.Length; i++) 
       { 
        if (a[i] == matchString) 
        { 
         matchIndex = i; 
         break; 
        } 
       } 
      } 

      sw.Stop(); 
      Console.WriteLine("Found via loop at index " + matchIndex + " in " + sw.Elapsed); 
      double loopTime = sw.Elapsed.TotalSeconds; 

      sw.Restart(); 

      for (int outer = 0; outer < COUNT; ++outer) 
      { 
       matchIndex = a.Select((r, i) => new { value = r, index = i }) 
          .Where(t => t.value == matchString) 
          .Select(s => s.index).First(); 
      } 

      sw.Stop(); 
      Console.WriteLine("Found via linq at index " + matchIndex + " in " + sw.Elapsed); 
      double linqTime = sw.Elapsed.TotalSeconds; 

      Console.WriteLine("Loop was {0} times faster than linq.", linqTime/loopTime); 
     } 
    } 
} 
+4

+1 के लिए – spajce

+2

समस्या नया ऑपरेटर है जो linq क्वेरी को धीमा कर देता है। यदि सरणी को linq की तुलना में किसी सूची में परिवर्तित किया जा सकता है तो FindIndex के साथ जोड़ा जा सकता है और इस बार लूप केवल 1.5 गुना तेज है। 'matchIndex = a.ToList()। FindIndex (x => x.Equals (matchString));' – JohnCambell

+0

आपकी लूप को नियमित लूप के करीब बदलने के लिए, नाटकीय रूप से अंतर को कम कर देता है: 'स्ट्रिंग tst = a.First (s => matchIndex ++! = - 2 && s == matchString); ' – jmoreno

3

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

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