2011-06-05 6 views
5
var res = new int[1000000].Skip(999999).First(); 

यह बहुत अच्छा होगा अगर यह क्वेरी 99 99 99 प्रविष्टियों को चलाने के बजाय सूचकांक का उपयोग करेगी।क्यों LINQ में ऑब्जेक्ट अनुकूलित करने के लिए छोड़ नहीं है?)

मैंने System.Core.dll पर एक नज़र डाली और देखा कि Skip() के विपरीत, Count() एक्सटेंशन विधि अनुकूलित है। यदि IEnumerableICollection लागू करता है तो यह केवल Count संपत्ति को कॉल करता है।

उत्तर

3

आप एक ऐसी ही सवाल का my answer को देखें, तो ऐसा लगता है जैसे कि यह एक गैर अनुभवहीन प्रदान करने के लिए आसान होना चाहिए किसी भी IList के लिए (यानी उचित अपवाद फेंकता) Skip के अनुकूलन:

public static IEnumerable<T> Skip<T>(this IList<T> source, int count) 
    { 
     using (var e = source.GetEnumerator()) 
      while (count < source.Count && e.MoveNext()) 
       yield return source[count++]; 
    } 

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

+0

मैं लिस्ट इटरेटर के MoveNext() का दुरुपयोग करने के बारे में भी सोचता हूं लेकिन यह एक हैक जैसा लगता है। वैसे भी महान विचार। – codymanix

3

मैं जॉन स्कीट इस जवाब दूँगा:

यदि हमारे अनुक्रम एक सूची है, हम बस सीधे इसके बारे में सही भाग को छोड़ सकते हैं और एक बार में एक आइटम प्राप्त हो सकते हैं। यह बहुत अच्छा लगता है, लेकिन अगर सूची बदलती है (या यहां तक ​​कि छोटा कर दिया गया है!) तो क्या हम इसके ऊपर फिर से चल रहे हैं? सरल इटरेटर के साथ काम करने वाला एक कार्यान्वयन आमतौर पर अपवाद फेंक देगा, क्योंकि परिवर्तन इटरेटर को अमान्य कर देगा। यह निश्चित रूप से एक व्यवहारिक परिवर्तन है। जब मैंने पहली बार छोड़ने के बारे में लिखा था, मैंने इसे "संभव" अनुकूलन के रूप में शामिल किया - और वास्तव में इसे एडुलिनक स्रोत कोड में बदल दिया। अब मैं इसे गलती मानता हूं, और इसे पूरी तरह से हटा दिया है।

...

इन "अनुकूलन" दोनों के साथ

समस्या यह है कि वे एक इटरेटर आस्थगित निष्पादन के लिए इस्तेमाल किया ब्लॉक के भीतर सूची के आधार पर अनुकूलन लागू कर रहे हैं यकीनन है। शुरुआती विधि कॉल के बिंदु पर या तत्काल निष्पादन ऑपरेटर (गणना, टोस्टिस्ट इत्यादि) के भीतर या तो सूचियों के लिए अनुकूलित करना ठीक है, क्योंकि हम मानते हैं कि अनुक्रम विधि के निष्पादन के दौरान अनुक्रम नहीं बदलेगा। हम एक इटरेटर ब्लॉक के साथ उस धारणा को नहीं बना सकते हैं, क्योंकि कोड का प्रवाह बहुत अलग है: कॉलर के MoveNext() के उपयोग के आधार पर हमारे कोड को बार-बार देखा जाता है।

https://msmvps.com/blogs/jon_skeet/archive/2011/01/26/reimplementing-linq-to-objects-part-40-optimization.aspx

+1

आपका उद्धरण सूचियों के बारे में है; ओपी का उदाहरण सरणी के बारे में है। चूंकि सरणी निश्चित लंबाई हैं, इसलिए उन्हें पुनरावृत्ति के दौरान बदला नहीं जा सकता है और उनके गणक को कोई अपवाद नहीं फेंकता है। – Gabe

+0

@Gabe - असल में, उस लेख का शीर्षक "हम LINQ में ऑब्जेक्ट्स में ऑप्टिमाइज़ नहीं कर सकते हैं?" इसलिए मुझे लगता है कि मैं आपके साथ असहमत हूं क्योंकि यह आलेख लिंक में ऑब्जेक्ट्स – IAmTimCorey

+0

में Skip() का उपयोग करने के बारे में है, मैंने हमेशा सोचा था कि LINQ IENumerables को केवल पढ़ने के लिए माना जाना चाहिए। मैं अब भी नहीं समझा। Skip का अनुकूलित संस्करण अभी भी एक गणनाकर्ता (केवल इंडेक्स एन से शुरू होता है) लौटाएगा, इस प्रकार सूची बदलती है तो सही तरीके से व्यवहार कर रहा है .. – codymanix