ToList () कॉल करते समय क्या कोई प्रदर्शन प्रभाव पड़ता है?


139

उपयोग करते समय ToList(), क्या कोई प्रदर्शन प्रभाव है जिस पर विचार करने की आवश्यकता है?

मैं एक निर्देशिका से फ़ाइलों को पुनः प्राप्त करने के लिए एक प्रश्न लिख रहा था, जो कि प्रश्न है:

string[] imageArray = Directory.GetFiles(directory);

हालांकि, जब से मैं List<>इसके बजाय काम करना पसंद करता हूं, तो मैंने ...

List<string> imageList = Directory.GetFiles(directory).ToList();

तो, क्या कुछ प्रकार के प्रदर्शन प्रभाव हैं, जिन्हें इस तरह से रूपांतरण करने का निर्णय लेने पर विचार किया जाना चाहिए - या केवल बड़ी संख्या में फ़ाइलों से निपटने पर विचार किया जाना चाहिए? क्या यह एक नगण्य रूपांतरण है?


+1 का जवाब यहां भी जानना चाहते हैं। IMHO, बशर्ते एप्लिकेशन प्रदर्शन महत्वपूर्ण है, मुझे लगता है कि मैं हमेशा एक का उपयोग करेंगे List<T>एक के पक्ष में T[]अगर यह कोड अधिक तार्किक / पठनीय / पोषणीय (जब तक पाठ्यक्रम रूपांतरण के बनाता था के कारण ध्यान देने योग्य प्रदर्शन की समस्याओं जो मामले में मैं फिर से चाहते हैं यह मुझे पता है)।
सिपस्टर

एक सरणी से एक सूची बनाना सुपर सस्ता होना चाहिए।
लेप्पी

2
@ सिस्टर मैं केवल डेटा प्रकार निर्दिष्ट करता हूं, विशेष रूप से जब मुझे नौकरी करने की आवश्यकता होती है। अगर मुझे फोन नहीं करना है Addया Remove, मैं इसे IEnumerable<T>(या और भी बेहतर var) छोड़
दूंगा

4
मुझे लगता है, इस मामले में इसके EnumerateFilesबजाय कॉल करना बेहतर है GetFiles, इसलिए केवल एक सरणी बनाई जाएगी।
तुकाफ

3
GetFiles(directory), जैसा कि वर्तमान में .NET में लागू किया गया है, बहुत अधिक है new List<string>(EnumerateFiles(directory)).ToArray()। तो GetFiles(directory).ToList()एक सूची बनाता है, उससे एक सरणी बनाता है, फिर एक सूची बनाता है। जैसा कि 2kay कहता है, आपको यहां करना पसंद करना चाहिए EnumerateFiles(directory).ToList()
जोरेन

जवाबों:


178

IEnumerable.ToList()

हां, IEnumerable<T>.ToList()प्रदर्शन प्रभाव पड़ता है, यह एक ओ (एन) ऑपरेशन है, हालांकि यह केवल प्रदर्शन महत्वपूर्ण संचालन में ध्यान देने की आवश्यकता होगी।

ToList()आपरेशन का उपयोग करेगा List(IEnumerable<T> collection)निर्माता। इस कंस्ट्रक्टर को सरणी की एक प्रतिलिपि (अधिक सामान्यतः IEnumerable<T>) बनानी होगी, अन्यथा मूल सरणी के भविष्य के संशोधन उस स्रोत पर T[]भी बदल जाएंगे जो आमतौर पर वांछनीय नहीं होगा।

मैं यह दोहराना चाहूंगा कि यह केवल एक बड़ी सूची के साथ एक फर्क पड़ेगा, स्मृति की विखंडन की नकल करना प्रदर्शन करने के लिए काफी तेज संचालन है।

आसान टिप, AsबनामTo

आप LINQ में देखेंगे कि कई तरीके हैं जो As(जैसे AsEnumerable()) और To(जैसे ToList()) से शुरू होते हैं। जिन तरीकों से शुरुआत Toहोती है, उनमें ऊपर की तरह रूपांतरण की आवश्यकता होती है (यानी प्रदर्शन को प्रभावित कर सकते हैं), और जिन तरीकों से शुरुआत Asहोती है, उन्हें बस कुछ कलाकारों या सरल ऑपरेशन की आवश्यकता होती है।

पर अतिरिक्त विवरण List<T>

यहाँ थोड़ा और अधिक विस्तार से बताया गया है कि List<T>आपकी रुचि के मामले में कैसे काम करता है :)

A List<T>एक निर्माण का भी उपयोग करता है जिसे डायनामिक एरे कहा जाता है जिसे मांग पर आकार देने की आवश्यकता होती है, यह ईवेंट एक पुराने एरे की सामग्री को नए एरे में कॉपी करता है। तो यह छोटा शुरू होता है और आवश्यकता पड़ने पर आकार में बढ़ जाता है

इस पर Capacityऔर Countविशेषताओं के बीच अंतर है List<T>Capacityदृश्यों के पीछे के सरणी के आकार को संदर्भित करता है, Countऐसी वस्तुओं की संख्या है List<T>जिसमें हमेशा होता है <= Capacity। इसलिए जब किसी आइटम को सूची में जोड़ा जाता है, तो उसे बढ़ाते हुए Capacity, आकार List<T>को दोगुना कर दिया जाता है और सरणी को कॉपी किया जाता है।


2
मैं बस उस List(IEnumerable<T> collection)पैरामीटर की जाँच पर जोर देना चाहता था यदि संग्रह पैरामीटर है ICollection<T>और फिर तुरंत आवश्यक आकार के साथ एक नया आंतरिक सरणी बनाता है। यदि पैरामीटर संग्रह नहीं है ICollection<T>, तो निर्माता इसके माध्यम से पुनरावृत्ति करता है और Addप्रत्येक तत्व के लिए कॉल करता है ।
जस्टिनस सिमानवीसियस

यह ध्यान रखना महत्वपूर्ण है कि आप अक्सर ToList () को भ्रामक रूप से मांग करने वाले ऑपरेशन के रूप में देख सकते हैं। ऐसा तब होता है जब आप एक IEnumerable <> througha LINQ क्वेरी बनाते हैं। linq क्वेरी का निर्माण किया गया है लेकिन निष्पादित नहीं किया गया है। कॉलिंग टोलिस्ट () क्वेरी को चलाएगा और इसलिए संसाधन गहन प्रतीत होगा - लेकिन यह वह क्वेरी है जो गहन है न कि टॉयलिस्ट () ऑपरेशन (जब तक यह वास्तव में बहुत बड़ी सूची नहीं है)
dancer42

36

क्या टोलिस्ट () को कॉल करने पर प्रदर्शन प्रभाव पड़ता है?

हां बिल्कुल। सैद्धांतिक रूप से भी i++एक प्रदर्शन प्रभाव पड़ता है, यह शायद कुछ टिक्स के लिए कार्यक्रम को धीमा कर देता है।

क्या करता .ToListहै?

जब आप आह्वान करते हैं .ToList, तो कोड कॉल Enumerable.ToList()करता है जो एक विस्तार विधि है return new List<TSource>(source)सबसे खराब परिस्थितियों में, संबंधित कंस्ट्रक्टर में, यह आइटम कंटेनर के माध्यम से जाता है और उन्हें एक के बाद एक नए कंटेनर में जोड़ता है। इसलिए इसका व्यवहार प्रदर्शन पर बहुत कम प्रभाव डालता है। आपके एप्लिकेशन की प्रदर्शन बोतल गर्दन होना असंभव है।

प्रश्न में कोड के साथ क्या गलत है

Directory.GetFilesफ़ोल्डर के माध्यम से चला जाता है और सभी फाइलों के नामों को तुरंत मेमोरी में वापस कर देता है , इसमें एक संभावित जोखिम है कि स्ट्रिंग [] बहुत मेमोरी खर्च करती है, सब कुछ धीमा कर देती है।

तब क्या किया जाना चाहिए

निर्भर करता है। यदि आप (साथ ही साथ आपके व्यावसायिक तर्क) गुरुते हैं कि फ़ोल्डर में फ़ाइल राशि हमेशा छोटी है, तो कोड स्वीकार्य है। लेकिन यह अभी भी एक आलसी संस्करण का उपयोग करने का सुझाव दिया गया है: Directory.EnumerateFilesC # 4 में। यह एक क्वेरी की तरह बहुत अधिक है, जिसे तुरंत निष्पादित नहीं किया जाएगा, आप इस पर अधिक क्वेरी जोड़ सकते हैं:

Directory.EnumerateFiles(myPath).Any(s => s.Contains("myfile"))

जो एक फाइल के रूप में पथ को खोजना बंद कर देगा जिसका नाम "myfile" है। यह स्पष्ट रूप से एक बेहतर प्रदर्शन है .GetFiles


19

क्या टोलिस्ट () को कॉल करने पर प्रदर्शन प्रभाव पड़ता है?

हाँ वहाँ है। विस्तार विधि का उपयोग करने से स्रोत संग्रह से Enumerable.ToList()एक नई List<T>वस्तु का निर्माण होगा IEnumerable<T>जिसमें निश्चित रूप से एक प्रदर्शन प्रभाव पड़ता है।

हालाँकि, यह समझने में List<T>मदद मिल सकती है कि प्रदर्शन प्रभाव महत्वपूर्ण है या नहीं।

List<T>T[]सूची के तत्वों को संग्रहीत करने के लिए एक सरणी ( ) का उपयोग करता है । एक बार आवंटित किए जाने के बाद List<T>ऐरे को बढ़ाया नहीं जा सकता है, इसलिए सूची के तत्वों को संग्रहीत करने के लिए एक ओवर-आकार सरणी का उपयोग करेगा। जब List<T>आकार से परे बढ़ता है तो अंतर्निहित सरणी को एक नया सरणी आवंटित करना पड़ता है और सूची बढ़ने से पहले पुराने सरणी की सामग्री को नए बड़े सरणी में कॉपी करना पड़ता है।

जब एक नया List<T>निर्माण किया जाता है IEnumerable<T>तो दो मामले होते हैं:

  1. स्रोत संग्रह लागू होता है ICollection<T>: फिर स्रोत संग्रह ICollection<T>.Countके सटीक आकार को प्राप्त करने के लिए उपयोग किया जाता है और स्रोत संग्रह के सभी तत्वों का उपयोग करके बैकिंग सरणी में कॉपी किए जाने से पहले एक मिलान बैकिंग सरणी आवंटित की जाती है ICollection<T>.CopyTo()। यह ऑपरेशन काफी कुशल है और संभवत: मेमोरी के ब्लॉक कॉपी करने के लिए कुछ सीपीयू इंस्ट्रक्शन में मैप करेगा। हालाँकि, प्रदर्शन की दृष्टि से नए एरे के लिए मेमोरी की आवश्यकता होती है और सभी तत्वों को कॉपी करने के लिए सीपीयू साइकिल की आवश्यकता होती है।

  2. अन्यथा स्रोत संग्रह का आकार अज्ञात है और IEnumerable<T>एक नए समय में प्रत्येक स्रोत तत्व को एक में जोड़ने के लिए एन्यूमरेटर का उपयोग किया जाता है List<T>। प्रारंभ में समर्थन सरणी खाली है और आकार 4 का एक सरणी बनाया गया है। फिर जब यह ऐरे बहुत छोटा हो जाता है तो आकार दोगुना हो जाता है इसलिए बैकिंग ऐरर इस तरह बढ़ता है जैसे 4, 8, 16, 32 आदि। हर बार बैकिंग ऐरे बढ़ने पर इसे फिर से लगाना पड़ता है और अब तक संग्रहीत सभी तत्वों को कॉपी करना पड़ता है। यह ऑपरेशन पहले मामले की तुलना में बहुत अधिक महंगा है, जहां सही आकार का एक सरणी तुरंत बनाया जा सकता है।

    इसके अलावा, अगर आपके स्रोत संग्रह में यह कहा गया है कि 33 तत्व सूची में 64 तत्वों की एक सरणी का उपयोग करके कुछ मेमोरी को बर्बाद कर देंगे।

आपके मामले में स्रोत संग्रह एक ऐसा सरणी है जो ICollection<T>प्रदर्शन को प्रभावित करता है इसलिए प्रदर्शन प्रभाव कुछ ऐसा नहीं है जिसके बारे में आपको चिंतित होना चाहिए जब तक कि आपका स्रोत सरणी बहुत बड़ा न हो। कॉलिंग ToList()बस स्रोत सरणी कॉपी और एक List<T>वस्तु में लपेट जाएगा । यहां तक ​​कि दूसरे मामले का प्रदर्शन भी छोटे संग्रह के लिए चिंता की बात नहीं है।


5

"क्या कोई प्रदर्शन प्रभाव है जिस पर विचार करने की आवश्यकता है?"

आपके सटीक परिदृश्य के साथ मुद्दा यह है कि सबसे पहले और प्रदर्शन के बारे में आपकी वास्तविक चिंता हार्ड ड्राइव की गति और ड्राइव के कैश की दक्षता से होगी।

उस दृष्टिकोण से, प्रभाव निश्चित रूप से इस बिंदु पर नगण्य है कि सं । पर विचार करने की आवश्यकता नहीं है।

लेकिन अगर आपको वास्तव में List<>संरचना की विशेषताओं की आवश्यकता है, तो संभवत: आपको अधिक उत्पादक बनाना होगा, या आपके एल्गोरिथ्म को अधिक अनुकूल बनाना होगा, या कुछ अन्य लाभ। अन्यथा, आप बिना किसी कारण के केवल जानबूझकर एक बेहूदा प्रदर्शन हिट जोड़ रहे हैं। जो मामले में, स्वाभाविक रूप से, आपको ऐसा नहीं करना चाहिए! :)


4

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

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

यदि आप किसी डेटा स्रोत के खिलाफ क्वेरीज़ का प्रदर्शन कर रहे हैं उदाहरण के लिए LINQ से SQL का उपयोग करने वाला डेटाबेस तो ToList करने की लागत बहुत अधिक है क्योंकि जब आप विलंबित निष्पादन यानी लोड आइटम करने के बजाय LINQ से SQL के साथ ToList का उपयोग करते हैं (जो कि फायदेमंद हो सकता है कई परिदृश्यों में) यह डाटाबेस से आइटम को तुरंत मेमोरी में लोड करता है


हारिस: जो मुझे मूल स्रोत के बारे में निश्चित नहीं है, वह तोलिस्ट () को कॉल करने के बाद मूल स्रोत का क्या होगा
टैलेंटट्यूनर

@ सौरभ जीसी इसे साफ करेंगे
pswg

@ सौरभ को मूल स्रोत से कुछ नहीं होगा। मूल स्रोत के तत्वों को नई बनाई गई सूची
हरिस हसन

"यदि आप केवल संग्रह के माध्यम से पुनरावृति करना चाहते हैं, तो आपको ToList प्रदर्शन करने की आवश्यकता नहीं है" - तो आपको इसे कैसे करना चाहिए?
शार्प

4

यह करने के रूप में कुशल के रूप में किया जाएगा:

var list = new List<T>(items);

यदि आप कंस्ट्रक्टर के स्रोत कोड को इकट्ठा करते हैं जो एक लेता है IEnumerable<T>, तो आप देखेंगे कि यह कुछ चीजें करेगा:

  • कॉल collection.Count, इसलिए यदि collectionहै एक IEnumerable<T>, यह निष्पादन के लिए बाध्य करेगा। यदि collectionएक सरणी, सूची, आदि है, तो यह होना चाहिए O(1)

  • यदि collectionलागू होता है ICollection<T>, तो यह ICollection<T>.CopyToविधि का उपयोग करके आंतरिक सरणी में आइटम को बचाएगा । यह चाहिए हो O(n), किया जा रहा है nसंग्रह की लंबाई।

  • यदि collectionलागू नहीं होता है ICollection<T>, तो यह संग्रह की वस्तुओं के माध्यम से पुनरावृत्ति करेगा, और उन्हें एक आंतरिक सूची में जोड़ देगा।

तो, हाँ, यह अधिक मेमोरी का उपभोग करेगा, क्योंकि इसे एक नई सूची बनानी होगी, और सबसे खराब स्थिति में, यह होगाO(n) , क्योंकि यह collectionप्रत्येक तत्व की प्रतिलिपि बनाने के लिए पुनरावृति करेगा ।


3
करीब, 0(n)जहां nमूल संग्रह में मौजूद बाइट्स का कुल योग है, तत्वों की गिनती नहीं है (अच्छी तरह से अधिक सटीक n = बाइट्स / शब्द आकार होने के लिए)
user1416420

@ user1416420 मैं गलत हो सकता हूं, लेकिन ऐसा क्यों है? क्या होगा अगर यह कुछ अन्य प्रकार (उदाहरण के लिए। का एक संग्रह है bool, intआदि)? आपको वास्तव में संग्रह में प्रत्येक स्ट्रिंग की प्रतिलिपि बनाने की आवश्यकता नहीं है। आप बस उन्हें नई सूची में जोड़ें।
ऑस्कर मेडरोस

अभी भी नई मेमोरी आवंटन और बाइट्स की नकल से कोई फर्क नहीं पड़ता है जो इस विधि को मार रहा है। .NET में 4 बाइट पर एक बूल भी कब्जा करेगा। वास्तव में .NET में किसी ऑब्जेक्ट का प्रत्येक संदर्भ कम से कम 8 बाइट्स लंबा होता है, इसलिए यह बहुत धीमा है। पहला 4 बाइट्स टाइप टेबल पर और दूसरा 4 बाइट्स उस वैल्यू या मेमोरी लोकेशन की ओर इशारा करते हैं, जहां वैल्यू का पता लगाना है
user1416420

3

फ़ाइल सूची को पुनः प्राप्त करने के प्रदर्शन को ध्यान में रखते हुए, ToList()नगण्य है। लेकिन वास्तव में अन्य परिदृश्यों के लिए नहीं। यह वास्तव में इस बात पर निर्भर करता है कि आप इसका उपयोग कहां कर रहे हैं।

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

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

  • एक पर कॉल करते समय IEnumerable<T>, आप (आमतौर पर एक क्वेरी) को भौतिक करते हैं IEnumerable<T>


2

ToList एक नई सूची बनाएगा और मूल स्रोत से नए बनाए गए सूची में तत्वों को कॉपी करेगा, इसलिए केवल मूल स्रोत से तत्वों की प्रतिलिपि बनाना है और स्रोत आकार पर निर्भर करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.