2014-10-22 20 views
6

मेरे पास एक कक्षा है जिसमें कुछ मूल प्रकार हैं। (3 एक्स फ्लोट, 2 एक्स int)।सी # एरे या एक वर्ग प्रकार के लिए सूची

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

अब सवाल कर रहे हैं:

  • मैं एक सूची के बजाय किसी सरणी से लाभ है?
  • क्या मैं एक ऐरे का उपयोग करके स्मृति को सहेजता हूं?
  • गति के बारे में क्या?

मैंने पढ़ा कि सी # में एक सूची आंतरिक रूप से ऐरे के रूप में भी लागू की गई है।

यदि यह सी ++ होगा, तो मुझे पता है कि सरणी पूरी वस्तु को पकड़ लेगी। लेकिन मुझे यकीन नहीं है कि कैसे सी # इसे संभालता है। क्या सी # सरणी केवल कक्षा के उदाहरणों के संदर्भ रखेगी या क्या यह पूर्ण डेटास्ट्रक्चर रखेगी?

+1

.NET में दोनों सरणी और सूचियां संदर्भ धारण करती हैं –

+0

मुझे लगता है कि आपको कुछ जवाब मिलेगा [यहां] (http://stackoverflow.com/questions/434761/array-versus-listt-when-to-use-which) – szpic

+0

स्मृति और गति के बारे में प्रश्नों के बारे में, क्या आपने उन्हें स्वयं तुलना की है? – rhughes

उत्तर

6

मूल रूप से सूची/सरणी अपरिवर्तनीय होगी, इस प्रकार मुझे अन्य धागे के साथ सिंक्रनाइज़ करने की आवश्यकता नहीं है।

आप T[] या List<T> के बजाय एक अपरिवर्तनीय संग्रह पर विचार किया? ImmutableArray<T> सबसे अधिक समझ में आता है। कुशल तरीके से संग्रह बनाने के लिए आप ImmutableArray<T>.Builder का उपयोग कर सकते हैं।

  • मैं एक सूची के बजाय किसी सरणी से लाभ है?

आप बदलना आप सरणी का उपयोग करना चाहिए तत्वों की संख्या की जरूरत नहीं है। यह उन सभी को स्पष्ट करेगा जो आपके कोड को देखते हैं कि आप तत्वों की संख्या नहीं बदल रहे हैं।

  • मैं किसी सरणी का उपयोग कर स्मृति को बचाने के है?

यह निर्भर करता है कि कैसे आप List<T> बनाएंगे। आंतरिक रूप से, जब आप List<T> पर तत्व जोड़ते हैं तो एक अंतर्निहित सरणी का आकार 2 * गुणक का उपयोग करके परिवर्तन होता है: जब नए तत्व के लिए पर्याप्त स्थान नहीं है, तो मौजूदा अंतर्निहित सरणी को दो बार आकार के साथ एक नया स्थान दिया जाता है। तो हाँ, आप सीधे ऐरे का उपयोग करके स्मृति को सहेज सकते हैं, क्योंकि आपके पास आवंटित कोई अनावश्यक स्मृति नहीं होगी। हालांकि, आप इसे List<T> का उपयोग करके प्राप्त कर सकते हैं, या तो कन्स्ट्रक्टर का उपयोग करके इसे बनाकर सूची सूची लेते हैं या TrimExcess विधि को कॉल करके सभी तत्वों को सूची में जोड़े जाने के बाद इसे प्राप्त कर सकते हैं।

  • गति के बारे में क्या?

सरणी का उपयोग करके आप तर्क यह है कि List<T> विधियों, गुण और इंडेक्सर संपत्ति कॉल अंतर्निहित सरणी कॉल करने के लिए अनुवाद करता है बचा सकते हैं। लेकिन आपको इसकी परवाह नहीं करनी चाहिए, यह अनजान होगा।

यदि यह सी ++ होगा, तो मुझे पता है कि सरणी पूरी वस्तु को पकड़ लेगी। लेकिन मुझे यकीन नहीं है कि कैसे सी # इसे संभालता है। क्या सी # सरणी केवल कक्षा के उदाहरणों के संदर्भ रखेगी या क्या यह पूर्ण डेटास्ट्रक्चर रखेगी?

यह निर्भर करता है। यदि आप संदर्भ प्रकार के रूप में अपना प्रकार परिभाषित करते हैं (class) दोनों सरणी और सूची केवल विशेष वस्तुओं का संदर्भ रखेगी। यदि आप इसे मान प्रकार (struct) के रूप में परिभाषित करते हैं, तो सरणी वास्तविक तत्वों को रखेगी।

+0

अपरिवर्तनीय सूची या सरणी प्रदर्शन समस्याओं के लिए जाने जाते हैं, वे सबसे अच्छी पसंद नहीं हैं, क्योंकि वे हर बार एक पूरी नई प्रतिलिपि बनाएंगे और यदि तत्व लाखों में हैं जो भी खराब हैं।समवर्ती संग्रह अपरिवर्तनीय सूची या सरणी से अधिक स्कोर करते हैं, लेकिन समवर्ती संग्रह में कोई सूची या सरणी प्रतिस्थापन नहीं है –

+0

यदि आपके कोड में I/O जैसी चीजों के बिना सरल गणना होती है और सरणी/सूचियों का भारी उपयोग होता है, तो आप एक सरणी होने की उम्मीद कर सकते हैं तेजी से आईएमई के बारे में दो बार। अंतर बड़ा हो सकता है; यदि आप सीपीयू बाध्य हैं तो यह निश्चित रूप से एक आसान जीत है जिसे आप ले सकते हैं। –

+0

@MrinalKamboj हाँ, यह सच है। आप बिल्डर वर्ग का उपयोग कर निर्माण ओवरहेड को कम कर सकते हैं। लेकिन फिर भी उस संरचना तक पहुंचने से एक सरल सरणी तक पहुंचने जितनी तेज़ नहीं होगी। प्रश्न यह है कि कुछ उपयोग के मामले के लिए और अधिक महत्वपूर्ण है - यदि आपको सबसे तेज़ समाधान की आवश्यकता है, तो एक सरणी का उपयोग करें, – MarcinJuraszek

0

मेरे विचार में आप यहाँ से बाहर आवश्यकताओं की जोड़ी है, मुझे उन्हें बुलेट बिंदुओं के रूप में निर्दिष्ट करते हैं:

  • नाव की तरह मानक .net प्रकार के साथ क्लास, पूर्णांक आदि

  • करने के लिए एक संग्रह की आवश्यकता है एक कुशल तरीके से उन्हें (उनमें से बहुत से, लाखों) स्टोर करें। सूची, ऐरे इत्यादि के बीच निर्णय लेने की आवश्यकता है

  • संग्रह ज्यादातर आकार में तय किया जाता है और शायद ही कभी आपको संग्रह आकार को बदलने की आवश्यकता होती है।

  • चाहते संग्रह अपरिवर्तनीय हो सकता है, इस प्रकार सुरक्षित थ्रेड

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

  • किसी सरणी सभी निरंतर आवंटन एक ही बार में क्या होगा के लिए, भले ही तत्व नहीं हैं, लेकिन सूची के लिए यह रूप में होगा और जब तत्व जोड़े जाएंगे। इस मामले में सूची

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

  • शुद्ध प्रदर्शन परिप्रेक्ष्य में, सरणी स्कोर एक सूची की तुलना में बेहतर है, और अधिक तुलनात्मक जानकारी के लिए लिंक निम्न देखें:

Performance of Arrays vs. Lists

https://softwareengineering.stackexchange.com/questions/221892/should-i-use-a-list-or-an-array

  • धागा सुरक्षा के लिए, उनमें से कोई भी काम नहीं करेगा, आपको या तो लॉक, म्यूटेक्स इत्यादि जैसे सिंक्रनाइज़ेशन निर्माण या बेहतर तरीके से उपयोग करने की आवश्यकता है system.collections.concurrent के तहत संग्रह में इसकी विस्तृत श्रृंखला है लेकिन कोई भी सूची बिल्कुल नहीं है, निकटतम ConcurrentBag होगा लेकिन यह एक अनुक्रमित सूची है, या आप मेरे कस्टम थ्रेड सुरक्षित सूची पर विचार करना चाहेंगे, जो रीडरवाइटर लॉक स्लिम का उपयोग करता है और काम करता है अच्छा के रूप में समवर्ती संग्रह:

    using System.Collections.Generic; 
    using System.Threading; 
    
    /// <summary> 
    /// Thread safe version of the List using ReaderWriterLockSlim 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    public class ThreadSafeListWithRWLock<T> : IList<T> 
    { 
        // Internal private list which would be accessed in a thread safe manner 
        private List<T> internalList; 
    
        // ReaderWriterLockSlim object to take care of thread safe acess between multiple readers and writers 
        private readonly ReaderWriterLockSlim rwLockList; 
    
        /// <summary> 
        /// Public constructor with variable initialization code 
        /// </summary> 
        public ThreadSafeListWithRWLock() 
        { 
         internalList = new List<T>(); 
    
         rwLockList = new ReaderWriterLockSlim(); 
        } 
    
        /// <summary> 
        /// Get the Enumerator to the Thread safe list 
        /// </summary> 
        /// <returns></returns> 
        public IEnumerator<T> GetEnumerator() 
        { 
         return Clone().GetEnumerator(); 
        } 
    
        /// <summary> 
        /// System.Collections.IEnumerable.GetEnumerator implementation to get the IEnumerator type 
        /// </summary> 
        /// <returns></returns> 
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
        { 
         return Clone().GetEnumerator(); 
        } 
    
        /// <summary> 
        /// Clone method to create an in memory copy of the Thread safe list 
        /// </summary> 
        /// <returns></returns> 
        public List<T> Clone() 
        { 
         List<T> clonedList = new List<T>(); 
    
         rwLockList.EnterReadLock(); 
    
         internalList.ForEach(element => { clonedList.Add(element); });    
    
         rwLockList.ExitReadLock(); 
    
         return (clonedList); 
        } 
    
        /// <summary> 
        /// Add an item to Thread safe list 
        /// </summary> 
        /// <param name="item"></param> 
        public void Add(T item) 
        { 
         rwLockList.EnterWriteLock(); 
    
         internalList.Add(item); 
    
         rwLockList.ExitWriteLock(); 
        } 
    
        /// <summary> 
        /// Remove an item from Thread safe list 
        /// </summary> 
        /// <param name="item"></param> 
        /// <returns></returns> 
        public bool Remove(T item) 
        { 
         bool isRemoved; 
    
         rwLockList.EnterWriteLock(); 
    
         isRemoved = internalList.Remove(item); 
    
         rwLockList.ExitWriteLock(); 
    
         return (isRemoved); 
        } 
    
        /// <summary> 
        /// Clear all elements of Thread safe list 
        /// </summary> 
        public void Clear() 
        { 
         rwLockList.EnterWriteLock(); 
    
         internalList.Clear(); 
    
         rwLockList.ExitWriteLock(); 
        } 
    
        /// <summary> 
        /// Contains an item in the Thread safe list 
        /// </summary> 
        /// <param name="item"></param> 
        /// <returns></returns> 
        public bool Contains(T item) 
        { 
         bool containsItem; 
    
         rwLockList.EnterReadLock(); 
    
         containsItem = internalList.Contains(item); 
    
         rwLockList.ExitReadLock(); 
    
         return (containsItem); 
        } 
    
        /// <summary> 
        /// Copy elements of the Thread safe list to a compatible array from specified index in the aray 
        /// </summary> 
        /// <param name="array"></param> 
        /// <param name="arrayIndex"></param> 
        public void CopyTo(T[] array, int arrayIndex) 
        { 
         rwLockList.EnterReadLock(); 
    
         internalList.CopyTo(array,arrayIndex); 
    
         rwLockList.ExitReadLock(); 
        } 
    
        /// <summary> 
        /// Count elements in a Thread safe list 
        /// </summary> 
        public int Count 
        { 
         get 
         { 
          int count; 
    
          rwLockList.EnterReadLock(); 
    
          count = internalList.Count; 
    
          rwLockList.ExitReadLock(); 
    
          return (count); 
         } 
        } 
    
        /// <summary> 
        /// Check whether Thread safe list is read only 
        /// </summary> 
        public bool IsReadOnly 
        { 
         get { return false; } 
        } 
    
        /// <summary> 
        /// Index of an item in the Thread safe list 
        /// </summary> 
        /// <param name="item"></param> 
        /// <returns></returns> 
        public int IndexOf(T item) 
        { 
         int itemIndex; 
    
         rwLockList.EnterReadLock(); 
    
         itemIndex = internalList.IndexOf(item); 
    
         rwLockList.ExitReadLock(); 
    
         return (itemIndex); 
        } 
    
        /// <summary> 
        /// Insert an item at a specified index in a Thread safe list 
        /// </summary> 
        /// <param name="index"></param> 
        /// <param name="item"></param> 
        public void Insert(int index, T item) 
        { 
         rwLockList.EnterWriteLock(); 
    
         if (index <= internalList.Count - 1 && index >= 0) 
         internalList.Insert(index,item); 
    
         rwLockList.ExitWriteLock(); 
        } 
    
        /// <summary> 
        /// Remove an item at a specified index in Thread safe list 
        /// </summary> 
        /// <param name="index"></param> 
        public void RemoveAt(int index) 
        { 
         rwLockList.EnterWriteLock(); 
    
         if (index <= internalList.Count - 1 && index >= 0) 
         internalList.RemoveAt(index); 
    
         rwLockList.ExitWriteLock(); 
        } 
    
        /// <summary> 
        /// Indexer for the Thread safe list 
        /// </summary> 
        /// <param name="index"></param> 
        /// <returns></returns> 
        public T this[int index] 
        { 
         get 
         { 
          T returnItem = default(T); 
    
          rwLockList.EnterReadLock(); 
    
          if (index <= internalList.Count - 1 && index >= 0) 
           returnItem = internalList[index];    
    
          rwLockList.ExitReadLock(); 
    
          return (returnItem); 
         } 
         set 
         { 
          rwLockList.EnterWriteLock(); 
    
          if (index <= internalList.Count - 1 && index >= 0) 
           internalList[index] = value; 
    
          rwLockList.ExitWriteLock(); 
         } 
        } 
    } 
    
0
  1. नहीं वास्तव में। आंतरिक रूप से सूचियां सिर्फ सादे सरणी होती हैं, और अतिरिक्त सूची में तत्वों के लिए काउंटर (सरणी में नहीं)। आप केवल अधिक खराब कार्यक्षमता होगी।
  2. यदि आप तत्वों की गिनती जानते हैं, और सूची प्रारंभ करते समय इसे सेट करते हैं, तो आप किसी भी स्मृति को सहेज नहीं पाएंगे। सूची उपयोग का उपयोग करने से स्मृति बहुत कम है, और सूची आकार तय होने पर यह तत्वों की गिनती पर निर्भर नहीं है। लेकिन यदि आप सटीक सूची आकार निर्दिष्ट नहीं करते हैं, तो जब आप नया तत्व जोड़ते हैं और सूची तत्वों की गिनती आंतरिक सरणी आकार से बड़ी होती है तो आंतरिक सरणी का आकार दोगुना हो जाएगा।
  3. नहीं। अधिकांश समय यह सादे सरणी के साथ काम करने जैसा ही होता है। आंतरिक सरणी पुन: आकार के समय को छोड़कर (लेकिन यह बहुत लंबा नहीं है, और सूची तय होने पर नहीं होगी)।

सी ++ Arrays और सूचियों में हमेशा इसके अंदर पूरी पूर्ण वस्तु को स्टोर नहीं करते हैं। उनमें केवल संदर्भ शामिल हो सकते हैं। .NET भाषाओं में वही बात (प्रबंधित सी ++ के लिए भी सही)। मूल्य-प्रकारों को संग्रहीत किया जाएगा। संदर्भ-प्रकारों को संग्रहीत किया जाएगा ... वस्तुओं के संदर्भ के रूप में।

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