2009-07-18 14 views
21

मैं .NET 3.5 (सी #) का उपयोग कर रहा हूं और मैंने सुना है कि सी # List<T>.ToArray का प्रदर्शन "खराब" है, क्योंकि यह स्मृति सभी तत्वों के लिए एक नई सरणी बनाने के लिए प्रतिलिपि बनाता है। क्या यह सच है?सी # सूची <T>.ToArray प्रदर्शन खराब है?

+0

आप को देखने के लिए [चाहते हो सकता है है यह बेहतर करने के लिए कॉल-tolist या toArray-इन-linq- प्रश्न] (http://stackoverflow.com/questions/1105990/is-it-better-to-call-tolist-or-toarray-in-linq-queries) – nawfal

उत्तर

43

नहीं है कि सच नहीं है लिया। प्रदर्शन अच्छा है क्योंकि यह सब कुछ करता है स्मृति सभी तत्वों (*) को एक नई सरणी बनाने के लिए प्रतिलिपि बनाता है।

बेशक यह "अच्छा" या "खराब" प्रदर्शन के रूप में परिभाषित करने पर निर्भर करता है।

(*) संदर्भ प्रकारों के लिए संदर्भ, मूल्य प्रकारों के लिए मान।

संपादित

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

public T[] ToArray() 
{ 
    T[] destinationArray = new T[this._size]; 
    Array.Copy(this._items, 0, destinationArray, 0, this._size); 
    return destinationArray; 
} 

बेशक, "अच्छा" या "खराब" प्रदर्शन केवल कुछ विकल्प के सापेक्ष एक अर्थ है। यदि आपके विशिष्ट मामले में, आपके लक्ष्य को प्राप्त करने के लिए एक वैकल्पिक तकनीक है जो मापने योग्य तेज़ है, तो आप प्रदर्शन को "खराब" मान सकते हैं। यदि ऐसा कोई विकल्प नहीं है, तो प्रदर्शन "अच्छा" (या "पर्याप्त पर्याप्त") है।

संपादित 2

टिप्पणी के जवाब में: "वस्तुओं की कोई फिर से निर्माण?":।।।

संदर्भ प्रकार के लिए कोई पुनर्निर्माण मूल्य प्रकारों के लिए मूल्यों को कॉपी कर रहे हैं, शिथिल के रूप में पुनर्निर्माण

+2

धन्यवाद जो, आपका जवाब बहुत अच्छा है!क्या आपके पास आगे चर्चा करने या दावे के आगे साबित करने के लिए कोई संबंधित दस्तावेज हैं - "यह सब एक नई सरणी बनाने के लिए सभी तत्वों (*) की स्मृति प्रतिलिपि बनाता है।" – George2

+0

धन्यवाद जो, ऐरे। कॉपी केवल प्रतिलिपि संदर्भ? वस्तुओं का पुन: निर्माण नहीं? – George2

+1

जॉर्ज। इसे देखो! या परावर्तक का उपयोग करें और पता लगाएं। ToArray के लिए यह इतना जटिल नहीं था, है ना? –

1

यह एक सरणी में नए संदर्भ बनाता है, लेकिन है कि बस केवल बात यह है कि उस विधि और क्या करना चाहिए सकता है ...

+0

आपका मतलब है कि संदर्भ की प्रतिलिपि बनाई गई है? – George2

19

कारण toArray()

  • कॉल करने के लिए, तो दिए गए मान नहीं है संशोधित करने के लिए, इसे एक सरणी के रूप में लौटने से यह तथ्य थोड़ा स्पष्ट हो जाता है।
  • यदि कॉलर से डेटा पर कई अनुक्रमिक पहुंच करने की अपेक्षा की जाती है, तो सूची <> पर एक सरणी के लिए प्रदर्शन लाभ हो सकता है।
  • यदि आपको पता है कि आपको लौटाए गए मान को किसी तृतीय-पक्ष फ़ंक्शन पर पास करना होगा जो किसी सरणी की अपेक्षा करता है।
  • कॉलिंग फ़ंक्शंस के साथ संगतता जिसे .NET संस्करण 1 या 1.1 के साथ काम करने की आवश्यकता है। इन संस्करणों में सूची <> प्रकार (या किसी भी सामान्य प्रकार, उस मामले के लिए) नहीं है।

कारण toArray कॉल करने के लिए नहीं()

  • फोन करने वाले कभी जोड़ सकते हैं या तत्वों को हटाने की जरूरत होती है, तो एक सूची <> बिल्कुल आवश्यक है।
  • प्रदर्शन लाभों की आवश्यकता नहीं है, खासकर अगर कॉलर अनुक्रमिक फैशन में डेटा तक पहुंच रहा है। सूची <> से सरणी में कनवर्ट करने का अतिरिक्त चरण भी है, जो प्रोसेसिंग समय लेता है।
  • कॉलर हमेशा सूची को एक सरणी में परिवर्तित कर सकता है।

से here

+2

अच्छा रिफर्न, लेकिन मेरे प्रश्न का सीधा जवाब नहीं है? मेरे प्रश्न का आपका उत्तर क्या है? – George2

+4

यह एकमात्र उत्तर है जिसे हम दे सकते हैं: सुधार हमेशा प्रदर्शन को कम करता है। आप सबसे अधिक सक्षम चीज नहीं कर सकते जो आप अभी भी सही कर सकते हैं। इसका आवेदन यह है कि आप कॉल नहीं करते हैं। ToArray() जब तक आपको वैसे भी नहीं करना है। –

+4

"... सूची में किसी सरणी के लिए प्रदर्शन लाभ हो सकता है <>।" - इसके लिए कोई सबूत? मेरे लिए एक मिथक की तरह लगता है। – Joe

1

प्रदर्शन सापेक्ष दृष्टि से समझना है वर्णित किया जा सकता है जो एक सूची के लिए एक सरणी परिवर्तित को कॉपी शामिल सरणी, और इसकी लागत सरणी के आकार पर निर्भर करेगी। लेकिन आपको उस लागत की तुलना अन्य कार्यक्रमों की तुलना में करना है जो आपके प्रोग्राम कर रहे हैं। आपने पहली जगह में सरणी डालने के लिए जानकारी कैसे प्राप्त की? अगर यह डिस्क, या नेटवर्क कनेक्शन, या डेटाबेस से पढ़कर था, तो स्मृति में एक सरणी प्रतिलिपि समय के लिए एक पता लगाने योग्य अंतर बनाने की संभावना नहीं है।

+0

"पहली जगह में सरणी में डाल दिया" का अर्थ है? – George2

+1

सरणी की प्रतिलिपि बनाने से पहले, आपको सरणी में स्टोर करने के लिए कुछ जानकारी प्राप्त करनी होगी, अन्यथा इसकी प्रतिलिपि बनाने का कोई कारण नहीं होगा। –

4

हां , यह सच है कि यह सभी तत्वों की स्मृति प्रतिलिपि करता है। क्या यह एक प्रदर्शन समस्या है? यह आपकी प्रदर्शन आवश्यकताओं पर निर्भर करता है।

List सभी तत्वों को पकड़ने के लिए आंतरिक रूप से एक सरणी है। अगर सूची सूची के लिए अब पर्याप्त नहीं है तो सरणी बढ़ जाती है। किसी भी समय ऐसा होता है, सूची सभी तत्वों को एक नई सरणी में कॉपी करेगी। यह हर समय होता है, और ज्यादातर लोगों के लिए जो कोई प्रदर्शन समस्या नहीं है।

उदा। एक डिफ़ॉल्ट कन्स्ट्रक्टर के साथ एक सूची क्षमता 16 पर शुरू होती है, और जब आप 1712 तत्व .Add() करते हैं, तो यह आकार 32 की एक नई सरणी बनाता है, 16 पुराने मानों की प्रतिलिपि बनाता है और 17 वें जोड़ता है।

आकार अंतर भी ToArray() निजी संदर्भ पारित करने के बजाय एक नया सरणी उदाहरण देता है।

+0

धन्यवाद chris166, मैं सिर्फ पुष्टि करना चाहता हूं कि केवल संदर्भ को ToArray के दौरान कॉपी किया गया है। ToArray के दौरान वस्तुओं का पुन: निर्माण नहीं? – George2

+1

हां, केवल संदर्भों की प्रतिलिपि बनाई गई है। सूची नहीं जानता कि आपकी वस्तुओं की गहरी प्रति कैसे बनाएं। अपवाद मूल्य प्रकार (structs, ints, युगल, enums आदि) हैं। – chris166

0

किसी भी प्रकार की सूची/आईसीलेक्शन के लिए जहां यह लंबाई जानता है, यह शुरुआत से बिल्कुल सही आकार की सरणी आवंटित कर सकता है।

T[] destinationArray = new T[this._size]; 
Array.Copy(this._items, 0, destinationArray, 0, this._size); 
return destinationArray; 

यदि आपका स्रोत प्रकार IEnumerable है (न कि किसी सूची/संग्रह) तो स्रोत है:

items = new TElement[4]; 
.. 
if (no more space) { 
    TElement[] newItems = new TElement[checked(count * 2)]; 
    Array.Copy(items, 0, newItems, 0, count); 
    items = newItems; 

यह आकार 4 में शुरू होता है और तेजी से बढ़ता है, हर बार यह स्थान से बाहर चलाता है दोहरीकरण। प्रत्येक बार जब यह दोगुना हो जाता है, तो उसे स्मृति को पुन: आवंटित करना होगा और डेटा को कॉपी करना होगा।

यदि हम स्रोत-डेटा आकार जानते हैं, तो हम इस मामूली ओवरहेड से बच सकते हैं। हालांकि ज्यादातर मामलों में सरणी आकार < = 1024, यह इतनी जल्दी निष्पादित होगा कि हमें इस कार्यान्वयन के विवरण के बारे में भी सोचने की आवश्यकता नहीं है।

संदर्भ: Enumerable.cs, List.cs (उन्हें में F12ing), जो जवाब

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