2010-07-26 13 views
13

मुझे दिलचस्पी थी कि LINQ का उपयोग करके मेरी कक्षाओं को सॉर्ट करना या आईसीओपरपेरबल इंटरफ़ेस और List.Sort को कार्यान्वित करना बेहतर होगा या नहीं। जब मैं LINQ कोड तेज था तो मैं काफी आश्चर्यचकित था।सूची क्यों है <> ऑर्डरब्य LINQ IComparable + सूची <> से बेहतर है। डीबग मोड में सॉर्ट करें?

परीक्षण करने के लिए, मैंने टेस्टसोर्ट के अपरिपक्व नाम के साथ एक बहुत ही सरल वर्ग बनाया, आईसीओपरपेबल लागू किया।

class TestSort: IComparable<TestSort> { 
    private int age; 
    private string givenName; 

    public int Age { 
     get { 
      return age; 
     } 
     set { 
      age = value; 
     } 
    } 

    public string GivenName { 
     get { 
      return givenName; 
     } 
     set { 
      givenName = value; 
     } 
    } 

    public TestSort(int age, string name) { 
     this.age = age; 
     this.givenName = name; 
    } 

    public int CompareTo(TestSort other) { 
     return this.age.CompareTo(other.age); 
    } 
} 

फिर एक साधारण प्रोग्राम यह कई बार सुलझाने के लिए - तरह ज्यादा सूची को कॉपी से ज्यादा महंगा था, इसलिए इस बात का प्रभाव पर ध्यान नहीं दिया जा सकता है।

class Program { 
    static void Main(string[] args) { 
     // Create the test data 
     string name = "Mr. Bob"; 

     Random r = new Random(); 
     var ts2 = new List<TestSort>(); 

     for (int i = 0; i < 100; i++) { 
      ts2.Add(new TestSort(r.Next(), name)); 
     } 

     DateTime start, end; 

     // Test List<>.Sort 
     start = DateTime.Now; 
     for (int i = 0; i < 100000; i++) { 
      var l = ts2.ToList(); 
      l.Sort(); 
     } 
     end = DateTime.Now; 

     Console.WriteLine("IComparable<T>: "); 
     Console.WriteLine((end - start).TotalMilliseconds); 


     // Test Linq OrderBy 
     start = DateTime.Now; 
     for (int i = 0; i < 100000; i++) { 
      var l = ts2.ToList(); 
      l = l.OrderBy(item => item.Age).ToList(); 
     } 
     end = DateTime.Now; 

     Console.WriteLine("\nLINQ: "); 
     Console.WriteLine((end - start).TotalMilliseconds); 

     Console.WriteLine("Finished."); 
     Console.ReadKey(); 
    } 
} 

मैं काफी निम्नलिखित उत्पादन प्राप्त करने के लिए हैरान था:

IComparable<T>: 
2965.1696 

LINQ: 
2181.1248 

कभी कभी LINQ 2000 के नीचे जाना होगा, और कभी कभी IComparable के बारे में 3000

जाना जब मैं यह एक सामान्य के साथ परीक्षण किया जाएगा List<Int>List.Sort लाइनक की गति 1/4 थी, जो लगभग 2000 में बनी थी।

तो LINQ केवल ab क्यों है मेरी कक्षा के लिए सामान्य प्रकार की 66% गति? क्या मैं IComparable के कार्यान्वयन के साथ कुछ गलत कर रहा हूँ?

अद्यतन: मैं सिर्फ रिलीज़ मोड में यह कर की कोशिश करने के बारे में सोचा, और हाँ, परिणाम अलग अलग था:

IComparable<T>: 
1593.0911 

Linq: 
1958.1119 

लेकिन मैं अभी भी बहुत पता करने के लिए क्यों IComparable डिबग मोड में धीमी है दिलचस्पी ।

+1

क्या आपने डीबग मोड (प्रोजेक्ट गुण) में ऑप्टिमाइज़ेशन सेट करने का प्रयास किया था और यह देखकर कि यह अभी भी धीमा है? यदि नहीं, तो यह समझा सकता है। – Gishu

+0

अनुकूलन कोड चालू है ... और मैं एक योगदान कारक के बजाय एक वास्तविक कारण की तलाश में हूं। मैं समस्या को हल करने की कोशिश नहीं कर रहा हूं, दोनों विधियां मेरे उद्देश्यों के लिए पर्याप्त तेज़ हैं, मैं सिर्फ यह जानना चाहता हूं कि क्यों। –

उत्तर

6

क्या आप वाकई सब कुछ JITed है उपाय शुरू करने से पहले, आप अलग-अलग परिणाम (मैं भी समय को मापने के Stopwatch वर्ग उपयोग करने की अनुशंसा) मिल सकता है करते हैं: ऊपर जोड़ने के बाद मेरे माप के अनुसार

var ll = ts2.ToList(); 
ll.Sort(); 
ll.OrderBy(item => item.Age).ToList(); 

(कोड), IComparable हमेशा तेज है (यहां तक ​​कि डीबग में भी)।

+0

आप कैसे सुनिश्चित करते हैं कि मापने से पहले चीजें JITed हैं? –

+0

भी। मेरे पीसी पर लगभग 900 बार परीक्षण करना, आईसीओम्पेर्बल तेज़ है। लेकिन अगर मैं 1000 से अधिक लूप करता हूं, तो LINQ तेज़ी से हो जाता है। तो शुरुआती LINQ सेटअप पर कुछ ओवरहेड है, लेकिन बार-बार उपयोग तेजी से समाप्त होता है। –

+0

कोड स्निपेट में, जब आप 'll.OrderBy()' को कॉल करते हैं, तो सूची पहले से ही पिछली पंक्ति पर क्रमबद्ध की जा चुकी है, इसलिए संभव है कि 'ऑर्डरबी()' कहलाए जाने पर कम गणना होनी चाहिए। क्या आप इसे अपने स्टॉपवॉच टेस्ट में सत्यापित कर सकते हैं, आप पहले से सॉर्ट की गई सूची में 'ऑर्डरबी()' को कॉल नहीं कर रहे हैं? – devlord

0

यह CompareTo विधि को कॉल करने का ओवरहेड हो सकता है जिसे रिहाई मोड में संकलित और चलाने के दौरान इनलाइन के साथ प्रतिस्थापित किया जाएगा।

1

सॉर्ट अपरिवर्तित क्विकॉर्ट का उपयोग करता है, जिसमें इसके सबसे खराब मामले में एन * एन जटिलता है। मुझे नहीं पता कि ऑर्डरबाई किस प्रकार उपयोग करती है लेकिन मुझे पता है कि यह उसी विधि का उपयोग नहीं करता है क्योंकि यह एक स्थिर प्रकार है, array.sort के विपरीत।

+1

ऑब्जेक्ट्स के लिए लिंक ऑर्डरबी एक स्थिर क्विकॉर्ट का उपयोग करता है, जैसा कि Array.Sort के विपरीत है जो अस्थिर Quicksort का उपयोग करता है। एल्गोरिदम की गति लागत में बहुत अंतर नहीं होना चाहिए। उनमें से दोनों ओ (एन लॉग एन) हैं। –

+1

क्या आपको पता है कि यह अनुकूलित है या फिर भी यह एक ही एन^2 सबसे खराब मामला है? – Stajek

0

मेरे लिए, मैं लिंक को आईसीओम्पेर्बल के साथ उपयोग करूंगा (जब यह सॉर्ट करने का सबसेमात्र तरीका है)। सूची, सरणी, आदि

CompareTo में भी

आप तुलना करने के लिए ... उदाहरण के लिए कई तरह से हो सकता है, आप कर सकते हैं: इस मामले में, आइटम एक TestSort: IComparable<TestSort>

var sorted = ll.OrderBy(item => item); // This automatically used age to compare, as it's defined in CompareTo 

ll किसी भी IEnumerable किया जा सकता है इस तरह कुछ:

public int CompareTo(TestSort other) { 
     return this.age != other.age ? this.age.CompareTo(other.age) : this.dateOfBirth.CompareTo(other.dateOfBirth); 
    } 
संबंधित मुद्दे