2012-04-24 20 views
22

मैंने अपनी कस्टम ऑब्जेक्ट्स पर LINQ सॉर्टिंग से Array.Sort की तुलना करने के लिए त्वरित परीक्षण एप्लिकेशन बनाया। ऐरे .ॉर्ट बहुत धीमा लगता है!LINQ की तुलना में Array.Sort() इतनी धीमी क्यों है?

class Person : IComparable<Person> 
{ 
    public int Age { get; set; } 
    public string Name { get; set; } 

    public int CompareTo(Person obj) 
    { 
     return this.Age.CompareTo(obj.Age); 
    } 

    public Person() 
    { } 

} 

तो मैं मुख्य() में अपने परीक्षण व्यक्तियों बनाया:

string name = "Mr. Tomek"; 

Random r = new Random(); 
int size = 10000000; 

DateTime start, end; 
Person[] people1 = new Person[size]; 
Person[] people2 = new Person[size]; 

for (int i = 0; i < size; i++) 
{ 
    people1[i] = new Person(); 
    people1[i].Age = r.Next(0, 10000); 
    people1[i].Name = name; 

    people2[i] = new Person(); 
    people2[i].Age = people1[i].Age; 
    people2[i].Name = people1[i].Name; 
} 

Array.Sort द्वारा सॉर्ट करने के लिए लिया है कि मैं मापा जाता है समय के बाद

मैं इस तरह अपने कस्टम वर्ग बनाया और LINQ द्वारा:

start = DateTime.Now; 
var sort = from s in people2 
      orderby s.Age 
      select s; 
end = DateTime.Now; 
Console.WriteLine("LINQ: "); 
Console.WriteLine((end - start).TotalMilliseconds); 

start = DateTime.Now; 
Array.Sort(people1,((Person p1, Person p2)=>{return p1.CompareTo(p2);})); 
end = DateTime.Now; 

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

Console.ReadLine(); 

Linq समय: के बारे में 1 या 2 मिलीसेकंड

ऐरे .ॉर्ट: 16 सेकंड्स से अधिक!

सभी सरणी क्रमबद्ध की जाती हैं (LINQ नए संग्रह और पत्तियां ओरिजिनल सरणी को बिना छेड़छाड़ करती है) लेकिन Array.Sort बेहद धीमी है! इसे कैसे समझाया जा सकता है? (DEBUG और रिलीज मोड में Array.Sort अत्यंत विफल रहता है)

मैंने Array.Sort के साथ सॉर्ट करते समय लैम्ब्डा अभिव्यक्ति के साथ कोड चिपकाया लेकिन यह इसके साथ और इसके समान है। (कक्षा व्यक्ति IComparable इंटरफ़ेस लागू करता है)

+2

आपको मेरे संबंधित प्रश्न में रुचि हो सकती है। http://stackoverflow.com/questions/10110013/order-of-linq-extension-methods-does-not-affect-performance –

+0

@TomaszSikora: आप बस 'Array.Sort (people1)' को कॉल करके सॉर्ट कर सकते हैं, क्योंकि 'IComparable ' कार्यान्वयन स्वचालित रूप से उपयोग किया जाता है। –

+0

मैंने कुछ नोटिस किया ... बड़े सरणी को सॉर्ट करते समय लिंक तेज है। Array.Sort तेज है जब ऐरे 100 000 से कम तत्वों से कम है। ऐसा क्यों हो रहा है? –

उत्तर

55

आपकी लिंक क्वेरी निष्पादित नहीं होती है क्योंकि आपको परिणाम नहीं मिलते हैं। इसे deferred execution कहा जाता है। क्वेरी केवल तभी निष्पादित की जाती है जब आप वास्तव में परिणामों पर गणना करते हैं।

क्वेरी निष्पादित करने के लिए var results = sort.ToArray() जैसे कुछ का उपयोग करें, तो आपको अधिक सटीक परिणाम मिलेंगे।

+49

कोड जो निष्पादित नहीं करता है हमेशा निष्पादन कोड निष्पादित करेगा! –

+8

मुझे उम्मीद है कि ओपी मूर्खतापूर्ण महसूस नहीं करेगा। यह एक ** बहुत ** आम मुद्दा/गलती है जिसे मैंने देखा है (और शायद मैंने स्वयं किया है): जब आप वास्तव में एक आईनेमरेबल की गणना कर रहे हों और जब आप इसे बदल रहे हों तो समझना या समझना नहीं। मुझे लगता है कि इससे अधिक आम बात यह है कि आप अपने आईनेमरेबल को कई बार समझाकर अपनी क्षमता का खर्च उठाते हैं। –

+0

@ ब्लेश हां, यह निश्चित रूप से पहली बात नहीं है जो लोगों को लिंक के बारे में पता है :) – Botz3000

14

LINQ आलसी है। आपके people2 को वास्तव में हल नहीं किया गया है, LINQ ने अभी एक अस्थायी "वादा ऑब्जेक्ट" बनाया है कि यह सॉर्ट किया जाएगा। इसे वास्तव में करने के लिए, आपको मूल्यांकन को Console.WriteLine क्रमबद्ध परिणाम से मजबूर करना होगा, इसे सूची/सरणी में परिवर्तित करें या इस तरह कुछ और करें।

और देखें: deferred execution

9

Linq बयान IEnumerable<T> या के जायके, इस (या कुछ भी yield कीवर्ड का उपयोग) वापसी केवल निष्पादित करता है जब आप पुनरावृति यह। अधिकांश पुस्तकालय पुस्तकालय पुस्तकालयों (सभी नहीं) are lazy/deferred से उपलब्ध हैं।

आप इसे पुन: सक्रिय नहीं कर रहे हैं, इसलिए आप वास्तव में इस तरह का प्रदर्शन नहीं कर रहे हैं।

आपको पूर्ण पुनरावृत्ति को मजबूर करने की आवश्यकता है। एक सूची में परिणाम चिपका पूरी तरह से पुनरावृति जाएगा लौटे गणनीय:

var sort = (from s in people2 
      orderby s.Age 
      select s).ToList(); 

उसके बाद ही आप सेब के लिए सेब की तुलना की जाएगी।

वास्तव में, एक तरह से (orderby) के मामले में, बस पहले आइटम का चयन एक पूर्ण यात्रा का कारण होगा के रूप में एक तरह से पूरी तरह से किया जाना इससे पहले कि आप पहले परिणाम लौट सकते हैं की जरूरत है:

var sort = from s in people2 
      orderby s.Age 
      select s; 

var s = sort.First(); 
1

इस भाग को बदलने का प्रयास करें और एक बार फिर से अपना परीक्षण करें।

start = DateTime.Now; 
    var sort = (from s in people2 
       orderby s.Age 
       select s).ToList(); 
    end = DateTime.Now; 

यह LINQ अभिव्यक्ति का मूल्यांकन करेगा।

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