2011-01-14 21 views
10

इस बयान के संदर्भ में पर लिखें,स्पष्टीकरण और एक सी # शब्दकोश

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

क्या पढ़ा और लिखना मतलब है? मेरी समझ यह है कि एक पठन एक ऐसा ऑपरेशन है जो एक कुंजी देखता है और इसके मूल्य का संदर्भ प्रदान करता है और एक लेखन एक ऑपरेशन है जो शब्दकोश से एक महत्वपूर्ण मूल्य जोड़ी जोड़ता है या हटा देता है। हालांकि, मुझे इसके बारे में कुछ भी निर्णायक नहीं मिल रहा है।

तो बड़ा सवाल यह है कि, थ्रेड सुरक्षित शब्दकोश को लागू करते समय, एक ऑपरेशन जो शब्दकोश में मौजूदा कुंजी के मान को अद्यतन करता है, पाठक या लेखक पर विचार करता है? मैं एक शब्दकोश में अद्वितीय कुंजी तक पहुंचने और उनके मानों को संशोधित करने के लिए कई धागे रखने की योजना बना रहा हूं, लेकिन थ्रेड नई कुंजी को जोड़/हटा नहीं पाएंगे।

स्पष्ट प्रभाव, मानते हुए कि मौजूदा मान को संशोधित करना शब्दकोश पर एक लेखन ऑपरेशन नहीं है, यह है कि थ्रेड सुरक्षित डिक्शनरी का मेरा कार्यान्वयन बहुत अधिक कुशल हो सकता है, क्योंकि मुझे हर बार एक विशेष लॉक प्राप्त करने की आवश्यकता नहीं होती है मैं मान को मौजूदा कुंजी पर अपडेट करने का प्रयास करता हूं।

.NET 4.0 से ConcurrentDictionary का उपयोग एक विकल्प नहीं है।

उत्तर

2

एक मौजूदा मूल्य अधिलेखन एक लिखने आपरेशन

+2

यह वास्तव में एक टिप्पणी है, सवाल का जवाब नहीं। लेखक के लिए प्रतिक्रिया छोड़ने के लिए कृपया "टिप्पणी जोड़ें" का उपयोग करें। – SliverNinja

+0

@ स्लिवरनिंजा, मुझे लगता है कि यह उत्तर मूल प्रश्न को संबोधित करता है "क्या एक ऑपरेशन जो शब्दकोश में मौजूदा कुंजी के मान को अद्यतन करता है, पाठक या लेखक पर विचार करें?"। – binki

-1

एक मूल्य में संशोधन के रूप में व्यवहार किया जाना चाहिए एक लिखने और एक रेस स्थिति प्रस्तुत करता है।

एक और धागा अपडेट mydict [5] होने के लिए मान लीजिए कि mydict के मूल मूल्य [5] = 42 एक थ्रेड अपडेट mydict [5] 112 होने के लिए करते हैं 837.

क्या करना चाहिए का मूल्य रहस्य [5] अंत में हो? धागे का क्रम इस मामले में महत्वपूर्ण है, यानी आपको यह सुनिश्चित करना होगा कि आदेश स्पष्ट है या वे नहीं लिखते हैं।

+1

जो आप वर्णन कर रहे हैं वह वास्तव में दौड़ की स्थिति नहीं है - क्योंकि किसी भी तरह से जो भी आखिरी जीतता है - और यदि आप एक्सेस लॉक करते हैं तो वही होगा। एक दौड़ की स्थिति कुछ ऐसा होगा: अगर (! Dict.ContainsKey (5)) dict (5, नया मान()) अब एक संभावित असंगतता उत्पन्न हुई है। – Neil

+0

@Neil मुझे लगता है कि यह एक दौड़ की स्थिति है, बस दौड़ की स्थिति नहीं है कि शब्दकोश के साथ सौदा कर सकते हैं। मैं पहले से ही guarentee के लिए कोड कोड है कि उत्तर में वर्णित दौड़ की स्थिति का प्रकार नहीं होता है। – Joshua

+3

@ जोशुआ - एक रेस शर्त शब्दकोष कोड के भीतर हो सकती है जो 'मैडिक्ट [5] = एक्स' लागू करती है लेकिन सेरिनस के 3 सेट स्टेटमेंट्स के बीच कोई दौड़ स्थिति मौजूद नहीं है। आखिरी जीत के मूल्य को कौन सेट करता है - यह सिर्फ सामान्य प्रोग्रामिंग का विवरण है। एक ऐसी स्थिति में एक दौड़ स्थिति होती है जहां आप राज्य की पिछली परीक्षा के आधार पर राज्य निर्धारित करते हैं। अपने स्वयं के x = 1 पर रेस कंडीशन x ++ कैन उत्पन्न नहीं हो सकता है। – Neil

0

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

एक महत्वपूर्ण है सबसे निश्चित रूप से एक लिखने बदलने ...

तुम क्या चाहते हो सकता है ReaderWriterLock

पर http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx

+2

मैंने जो भी दस्तावेज पढ़ा था, वह दिखाता है कि रीडर/राइटर लॉक को सदमे से खराब प्रदर्शन करने के लिए, केवल एक लॉक का उपयोग करने से भी बदतर है। ऐसा लगता है कि रीडरवाइटर लॉकस्लिम का उपयोग करना चाहिए यदि आप उपलब्ध हैं या कुछ और उपयोग करते हैं। http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx –

+0

@Erik -I सहमत हैं, लेकिन जोड़ देंगे: यह हमेशा एक संतुलन है। इसे मिश्रण में अन्य लागतों पर निर्भर होना होगा। यदि पढ़ने और लिखने की मात्रा बराबर होती है तो मैं केवल लॉक() का उपयोग करने की सलाह दूंगा - लेकिन अगर लेखन दुर्लभ है - और आमतौर पर पाठक लेखक लॉक शायद ठीक है। अपग्रेड करते समय स्लिम लॉक पर जाना आसान होगा। जब आपको कोई समस्या हो तो प्रोफाइलिंग प्राप्त करने का सबसे अच्छा तरीका है। बहुत से लोग प्रति ऑपरेशन मिलीसेकंड को बचाने के लिए दिन कोडिंग करते हैं। – Neil

+0

सहमत हैं, कभी-कभी डेवलपर प्री-ऑप्टिमाइज़ करने की कोशिश कर रहे बहुत अधिक खर्च करते हैं। मैंने यह संकेत देने के लिए "चौंकाने वाला खराब प्रदर्शन" वाक्यांश का उपयोग किया, ऐसा लगता है कि यह एक सूक्ष्म प्रदर्शन मुद्दा नहीं बल्कि एक कठिन है। इसका उपयोग करने के बजाए इसे टालने के लिए आमतौर पर बेहतर माना जाता है। कम से कम, ऐसा लगता है कि विभिन्न प्रदर्शन चर्चाओं के दौरान मैंने देखा कि कई निष्कर्ष निकाले गए हैं। –

0

एक मूल्य के अपडेट कर रहा है देखने के लिए है करने के लिए धारणात्मक एक लिखने ऑपरेशन है। एक समवर्ती पहुंच के साथ एक मान को अपडेट करते समय जहां एक लिखने से पहले एक पठन पूरा किया जाता है, तो आप एक पुराना मान पढ़ते हैं। जब दो संघर्ष लिखते हैं तो गलत मान संग्रहीत किया जा सकता है।

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

आईसीओलेक्शन provides a member to synchronize access और संदर्भ बढ़ने/घटाने के संचालन में मान्य रहता है।

+0

यह एक दिलचस्प बिंदु है, यदि मैं और डालने का एक शब्दकोश घोषित करता हूं ("कुंजी 1", "हैलो") तो निर्देशिका ["Key1"] = "यह वास्तव में वास्तव में लंबी स्ट्रिंग है", क्या यह होगा मूल्य के लिए स्मृति आवंटित करना होगा, या चूंकि मान एक निष्कर्ष निकाला गया है, और ऑब्जेक्ट को ऑब्जेक्ट के लिए आवंटित कर दिया गया है, यह उस स्मृति को फिर से उपयोग करने में सक्षम होगा? मुझे लगता है कि बहुत कुछ शब्दकोश वस्तु के अंदरूनी हिस्सों पर निर्भर करेगा। – Joshua

+0

शब्दकोश के लिए <स्ट्रिंग, स्ट्रिंग> अंतर्निहित भंडारण आईसीओलेक्शन > है। तथ्य यह है कि आपने पहले से ही एक मान डाला है, इसका मतलब है कि रिकॉर्ड आईसीओलेक्शन में जोड़ा गया था (इसकी सामग्री का विस्तार करना, आवश्यक होने पर मेमोरी बढ़ाना)। सामग्री केवल एक स्ट्रक्चर है जिसमें दो स्ट्रिंग ऑब्जेक्ट्स का संदर्भ होता है। किसी अन्य चीज़ पर शब्दकोश मान स्ट्रिंग को बदलना बस स्मृति में एक नई स्ट्रिंग बनाता है और KeyValuePair संदर्भ को अद्यतन करता है। IDictionary अंतर्निहित स्टोरेज आकार में कोई बदलाव नहीं। –

+0

इसके अलावा, अगर आप एक ही कुंजी को दो बार डालने का प्रयास करते हैं तो सम्मिलन एक अपवाद फेंक देगा। यह आसानी से एक बहु थ्रेडेड वातावरण में हो सकता है जहां लॉकिंग ठीक से लागू नहीं किया गया था। यदि आप सुरक्षित होना चाहते हैं, तो केवल एक मौजूदा कुंजी तक पहुंचने से इसे बनाया जाएगा। यदि यह अस्तित्व में है तो इसे अपडेट किया जाएगा। कोई अपवाद फेंकना नहीं। यदि एक ही कुंजी जोड़ना एक वास्तविक त्रुटि स्थिति है जिसे आप पकड़ना चाहते हैं तो सम्मिलित करें का उपयोग करें। निर्देशिका। प्रविष्ट करें ("कुंजी 1", "हैलो"); बनाम निर्देशिका ["कुंजी 1"] = "हैलो"; –

0

एक पठन ऑपरेशन कुछ भी है जो Dictionary से एक कुंजी या मूल्य प्राप्त करता है, एक लेखन ऑपरेशन कुछ भी है जो कुंजी या मूल्य को अपडेट या जोड़ता है। इसलिए एक कुंजी को अपडेट करने की प्रक्रिया को लेखक माना जाएगा।

एक धागा सुरक्षित शब्दकोश बनाने के लिए एक आसान तरीका IDictionary कि बस एक म्युटेक्स ताले की अपनी खुद की कार्यान्वयन बनाने के लिए है और फिर एक कार्यान्वयन के लिए कॉल अग्रेषित करता है:

public class MyThreadSafeDictionary<T, J> : IDictionary<T, J> 
{ 
     private object mutex = new object(); 
     private IDictionary<T, J> impl; 

     public MyThreadSafeDictionary(IDictionary<T, J> impl) 
     { 
      this.impl = impl; 
     } 

     public void Add(T key, J value) 
     { 
     lock(mutex) { 
      impl.Add(key, value); 
     } 
     } 

     // implement the other methods as for Add 
} 

आप एक पाठक के साथ म्युटेक्स बदल सकते -writer लॉक अगर आपके पास कुछ धागे हैं तो केवल शब्दकोष पढ़ें।

यह भी ध्यान दें कि Dictionary ऑब्जेक्ट्स बदलती कुंजी का समर्थन नहीं करते हैं; इच्छित इच्छा प्राप्त करने का एकमात्र सुरक्षित तरीका मौजूदा कुंजी/मूल्य जोड़ी को हटाना और अद्यतन कुंजी के साथ एक नया जोड़ना है।

+0

क्या ConcurrentDictionary का उपयोग करने के बजाय ऐसा करने का कोई कारण है? – mcmillab

3

एक प्रमुख बिंदु अभी तक का उल्लेख नहीं किया है कि अगर TValue एक वर्ग प्रकार है, एक Dictionary<TKey,TValue> द्वारा आयोजित बातें TValue वस्तुओं की पहचान हो जाएगा। यदि किसी को शब्दकोश से संदर्भ प्राप्त होता है, तो शब्दकोश को न तो उस वस्तु के साथ किसी भी चीज़ के बारे में पता नहीं होगा और न ही किसी के बारे में परवाह करेगा।

एक मामलों में उपयोगी छोटे उपयोगिता वर्ग जहां एक शब्दकोश के साथ जुड़े कुंजी के सभी कोड के लिए इसका इस्तेमाल करने की जरूरत है कि के अग्रिम में जाना जाता हो जाएगा:

class MutableValueHolder<T> 
{ 
    public T Value; 
} 

एक मल्टी-थ्रेडेड कोड है चाहता है गिनें कि फाइलों के समूह में कितनी बार विभिन्न तार दिखाई देते हैं, और कोई भी ब्याज के सभी तारों को पहले से जानता है, फिर कोई उस उद्देश्य के लिए Dictionary<string, MutableValueHolder<int>> जैसा कुछ उपयोग कर सकता है। एक बार शब्दकोश को सभी उचित तारों और MutableValueHolder<int> प्रत्येक के लिए उदाहरण के साथ लोड किया जाता है, तो किसी भी संख्या में थ्रेड MutableValueHolder<int> ऑब्जेक्ट्स के संदर्भ पुनर्प्राप्त कर सकते हैं, और Threading.Interlocked.Increment या Value को संशोधित करने के लिए अन्य सभी विधियों को संशोधित करने के लिए, बिना किसी लिखने के शब्दकोश में बिल्कुल।

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