2010-09-21 22 views
5

आज एक प्रोग्रामिंग चर्चा के दौरान एक दोस्त और मैं थोड़ा परेशान थे। उदाहरण के तौर पर, हमने List<int> एन यादृच्छिक पूर्णांक (आमतौर पर 1.000.000) रखने की एक फिक्टिव समस्या बनाई है और एक ऐसा फ़ंक्शन बनाना चाहता था जो सभी इंटीग्रियों के सेट को वापस कर देता है जिसमें से एक से अधिक थे। बहुत सीधी चीजें। हमने इस समस्या को हल करने के लिए एक LINQ कथन बनाया है, और एक सादा सम्मिलन प्रकार आधारित एल्गोरिदम।LINQ संचालन सामान्य लूप से तेज क्यों हो सकता है?

अब, जैसा कि हमने गति की जांच की थी (कोड System.Diagnostics.StopWatch का उपयोग करके), परिणाम भ्रमित थे। LINQ कोड ने केवल सरल प्रकार से बेहतर प्रदर्शन नहीं किया, लेकिन यह से एकforeach/for है जो केवल सूची का एक लूप था, और इसमें कोई ऑपरेशन नहीं था (जो, एक साइड ट्रैक पर, मैंने सोचा था कंपाइलर को पूरी तरह से खोजना और निकालना था)।

यदि हमने कार्यक्रम के उसी निष्पादन में यादृच्छिक संख्याओं का एक नया List<int> उत्पन्न किया है और फिर LINQ कोड चलाया है, तो प्रदर्शन परिमाण (आमतौर पर हजारों) के आदेशों से बढ़ेगा। खाली लूप का प्रदर्शन बिल्कुल वही था।

तो, यहां क्या चल रहा है? क्या सामान्य लूप को बेहतर बनाने के लिए समानांतरता का उपयोग कर LINQ है? ये परिणाम कैसे संभव हैं? LINQ Quicksort का उपयोग करता है जो n * log (n) पर चलता है, जो प्रति परिभाषा पहले से धीमी है।

और दूसरे रन पर प्रदर्शन छलांग पर क्या हो रहा है?

हम दोनों इन परिणामों पर परेशान और चिंतित थे और समुदाय की कुछ स्पष्ट अंतर्दृष्टि की उम्मीद कर रहे थे, बस अपनी जिज्ञासा को पूरा करने के लिए।

+12

कृपया कुछ कोड पोस्ट करें। –

+1

शायद आप अपना परीक्षण साझा कर सकते हैं? –

+12

अपना कोड पोस्ट करें। आप शायद [स्थगित निष्पादन] (http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx) पर विचार नहीं कर रहे हैं। –

उत्तर

13

निस्संदेह आपने वास्तव में क्वेरी नहीं की है, आपने इसे केवल परिभाषित किया है। LINQ एक अभिव्यक्ति वृक्ष बनाता है जिसका वास्तव में मूल्यांकन नहीं किया जाता है जब तक आप एक ऐसा ऑपरेशन नहीं करते जिसके लिए गणना की आवश्यकता होती है। क्वेरी को मूल्यांकन करने के लिए मजबूर करने के लिए LINQ क्वेरी में ToList() या Count() ऑपरेशन जोड़ने का प्रयास करें।

आपकी टिप्पणी के आधार पर मुझे उम्मीद है कि यह आपके द्वारा किए गए कार्यों के समान है। नोट: यदि क्वेरी यथासंभव कुशल है तो मैंने यह पता लगाने में कोई समय नहीं लगाया है; मैं सिर्फ कुछ क्वेरी को यह बताने के लिए चाहता हूं कि कोड कैसे संरचित किया जा सकता है।

var dataset = ... 

var watch = Stopwatch.StartNew(); 

var query = dataset.Where(d => dataset.Count(i => i == d) > 1); 

watch.Stop(); // timer stops here 

foreach (var item in query) // query is actually evaluated here 
{ 
    ... print out the item... 
} 
+0

नकारात्मक: हमने डेटासेट को यह सत्यापित करने के लिए मुद्रित किया कि यह वास्तव में वह कर रहा था जो वह कर रहा था। – Pedery

+2

@ पेडरी - लेकिन क्या आपने इसे समय कोड अनुभाग या उसके बाहर से प्रिंट किया था। प्रिंट करने के लिए इसे छेड़छाड़ करने का मूल्यांकन किया जाएगा, लेकिन यदि आपने उस लूप को समय नहीं दिया जहां इसे मुद्रित किया गया था तो मूल्यांकन समय लूप के बाहर किया जाएगा। – tvanfosson

+0

हमने linq के परिणाम को एक var में सौंपा, फिर इसे समय क्षेत्र के बाहर मुद्रित किया। – Pedery

1

मैं सुझाव दूंगा कि LINQ केवल 'सामान्य पाश' से तेज़ है जब आपका एल्गोरिदम सही से कम होता है (या आपको अपने कोड में कुछ समस्या है)। तो यदि आप एक कुशल सॉर्टिंग एल्गोरिदम, आदि नहीं लिखते हैं तो LINQ तेज़ होगा।

LINQ आमतौर पर 'सामान्य तेज़' या 'सामान्य लूप की गति' के करीब 'बंद हो सकता है' कोड/डीबग/पढ़ने के लिए तेज़ (और सरल) हो। इसका लाभ है - निष्पादन गति नहीं।

यदि यह खाली लूप से तेज़ प्रदर्शन कर रहा है, तो आप कुछ गलत कर रहे हैं। टिप्पणियों में सुझाए गए अनुसार, आप स्थगित निष्पादन पर विचार नहीं कर रहे हैं और LINQ कथन वास्तव में निष्पादित नहीं कर रहा है।

+0

जैसा कि मैंने ऊपर एक टिप्पणी में कहा था, हमने उस डेटासेट को मुद्रित किया था जो यह उत्पादन कर रहा था और सभी क्रम में लग रहे थे। – Pedery

+0

स्टॉपवॉच बंद होने से पहले आपको इसे प्रिंट करना होगा। प्रिंटिंग बहुत धीमी है, हालांकि - इसे सूची में डंप करना सबसे अच्छा है। –

+0

हे, बीसीएल में जो कुछ भी मैंने लिखा है उससे तुलना करते हुए, हाँ, मेरा पूरा कोड बिल्कुल सही है। : ओ –

1

आप "अनुकूलन कोड" को सक्षम करने पर संकलन नहीं था, तो आप शायद इस व्यवहार देखना होगा। (यह निश्चित रूप से समझाएगा कि खाली लूप क्यों नहीं हटाया गया था।)

हालांकि, LINQ अंतर्निहित कोड पहले से संकलित कोड का हिस्सा है, जिसे निश्चित रूप से अनुकूलित किया जाएगा (जेआईटी, NGen या इसी तरह से)।

+0

+1 अच्छा बिंदु! मैं कोड अनुकूलन के संबंध में कंप्यूटर की वीएस डिफ़ॉल्ट सेटिंग्स को जांचना भूल गया। – Pedery

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