2012-07-27 6 views
17

काफी सरल: ConcurrentDictionary के अलावा (जो मैं उपयोग करूँगा लेकिन यह वास्तव में सही अवधारणा नहीं है), क्या कोई समवर्ती संग्रह (IProducerConsumer कार्यान्वयन) है जो किसी आइटम की सामान्य समानता के आधार पर विशिष्ट वस्तुओं को हटाने का समर्थन करता है या निकालने के लिए एक शर्त परिभाषित एक भविष्यवाणी?समवर्ती संग्रह एक निर्दिष्ट आइटम को हटाने का समर्थन करता है?

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

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

मैं एक ConcurrentBag उपयोग करने के लिए योजना बनाई थी, लेकिन केवल हटाने विधि (TryTake) बैग, नहीं एक निर्धारित एक से एक मनमाना आइटम को हटा (और ConcurrentBag .NET 4 में धीमी गति से है)। ConcurrentQueue और ConcurrentStack भी अगले एक के अलावा किसी अन्य आइटम को हटाने की अनुमति नहीं देता है, जो आपको प्रदान करेगा, जिससे ConcurrentDictionary छोड़ दिया जाएगा, जो काम करेगा लेकिन मुझे इसकी आवश्यकता से अधिक है (मुझे वास्तव में आवश्यक रिकॉर्ड के आईडी को स्टोर करना है; वे वर्कफ़्लो के दौरान नहीं बदलते हैं)।

+0

आप ReaderWriterLockSlim और एक सूची का उपयोग कर के बारे में कैसा महसूस करते हैं? या शायद अपने स्वयं के समवर्ती संग्रह – Frobzig

+1

@Frobzig रोलिंग - हल्के से रुचि रखने के लिए Ambivalent। मुझे समवर्ती संग्रह पसंद हैं क्योंकि वे सिर्फ काम करते हैं; बहुत कम कोड शामिल है। – KeithS

उत्तर

14

कारण इस तरह की कोई डेटा संरचना नहीं है कि सभी संग्रहों में O(n) का लुकअप ऑपरेशन समय है। ये IndexOf, Remove(element) आदि हैं। वे सभी सभी तत्वों के माध्यम से गणना करते हैं और समानता के लिए उन्हें जांचते हैं।

केवल हैश तालिकाओं हे की देखने का समय है (1)। समवर्ती परिदृश्य में ओ (एन) लुकअप समय संग्रह के बहुत लंबे लॉक का कारण बन जाएगा। अन्य धागे इस समय के दौरान तत्वों को जोड़ने में सक्षम नहीं होंगे।

शब्दकोश में केवल सेल हैश ने टक्कर मार दी लॉक किया जाएगा। अन्य थ्रेड जोड़ना जारी रख सकते हैं जबकि कोई हैश सेल के तत्वों के माध्यम से समानता की जांच कर रहा है।

मेरी सलाह पर जाने के लिए और ConcurrentDictionary का उपयोग करें।


वैसे, आप सही हैं कि ConcurrentDictionary आपके समाधान के लिए थोड़ा अधिक oversized है। आपको वास्तव में क्या चाहिए, यह देखने के लिए कि ऑब्जेक्ट काम में है या नहीं, जल्दी मौसम की जांच करना है। HashSet इसके लिए एकदम सही होगा। यह मूल रूप से Add(element), Contains(element), Remove(element) पर कुछ भी नहीं करता है।जावा में ConcurrentHeshSet कार्यान्वयन है। सी # के लिए मुझे यह मिला: How to implement ConcurrentHashSet in .Net यह नहीं पता कि यह कितना अच्छा है।

पहले चरण के रूप में मैं HashSet इंटरफ़ेस ConcurrentDictionary के साथ इंटरफ़ेस के साथ एक रैपर लिखता हूं, इसे ऊपर लाकर चलाता हूं और फिर विभिन्न कार्यान्वयन का प्रयास करता हूं और प्रदर्शन अंतर को देखता हूं।

1

यह वास्तव में सामान्य ज्ञान में संग्रह थ्रेड-सुरक्षित बनाने के लिए कठिन है। ऐसे कई कारक हैं जो थ्रेड-सुरक्षा में जाते हैं जो लाइब्रेरी/फ्रेमवर्क क्लास की जिम्मेदारी या दायरे से बाहर हैं जो वास्तव में "थ्रेड-सुरक्षित" होने की क्षमता को प्रभावित करते हैं ... जैसा कि आपने इंगित किया है उनमें से एक कमी प्रदर्शन प्रदर्शन है। एक प्रदर्शन संग्रह लिखना असंभव है जो थ्रेड-सुरक्षित है क्योंकि इसे सबसे खराब मानना ​​है ...

आम तौर पर अनुशंसित अभ्यास आप जो भी संग्रह चाहते हैं उसका उपयोग करना और थ्रेड-सुरक्षित तरीके से एक्सेस करना है। यह मूल रूप से ढांचे में अधिक धागा-सुरक्षित संग्रह क्यों नहीं है। इस पर अधिक http://blogs.msdn.com/b/bclteam/archive/2005/03/15/396399.aspx#9534371

+0

संग्रह के थ्रेड सुरक्षित पहुंच और थ्रेड सुरक्षित संग्रह तक पहुंच के बीच का अंतर काफी बड़ा हो सकता है। यदि धागे की संख्या बड़ी है और वे जो ऑपरेशन कर रहे हैं वे गैर-तुच्छ हैं, तो प्रत्येक धागे पर एक बड़ी बाधा हो सकती है जो अपने लॉक को हासिल करने और साफ़ करने के लिए प्रतीक्षा कर रही है। मुझे लगता है कि आप लॉक ऑब्जेक्ट्स (जैसे प्रत्येक हैश के अनुरूप) के मनमाने ढंग से बड़े संग्रह को बनाए रख सकते हैं, लेकिन यह बहुत गन्दा होगा ... –

+0

@PatrickM एक विशेष अनुप्रयोगों को संग्रह थ्रेड-सुरक्षित तक पहुंचने के लिए संचालन का सेट बहुत अधिक है प्रत्येक परिदृश्य में संग्रह थ्रेड-सुरक्षित बनाने से कम उपयोग किया जा सकता है। किसी भी दिए गए ऑब्जेक्ट (संग्रह या नहीं) थ्रेड-सुरक्षित तक पहुंच बनाने के लिए आपको केवल एक लॉक ऑब्जेक्ट की आवश्यकता होनी चाहिए। सभी समवर्ती * संग्रह केवल एक लॉक ऑब्जेक्ट का उपयोग करते हैं। –

+0

कई मामलों में, सामान्य थ्रेड-सुरक्षित संग्रहों को डिज़ाइन करना मुश्किल नहीं है जो सामान्य इंटरफेस के कुछ सबसेट्स को लागू करते हैं (उदा। 'IList ' जो 'Add' और लिखने-द्वारा-इंडेक्स को केवल उत्परिवर्तन विधियों के रूप में समर्थित करता है)। ऐसी चीजें संग्रह से अधिक कुशल हो सकती हैं जो अधिक सामान्यीकृत पहुंच प्रदान करती हैं, लेकिन फ्रेमवर्क में दुर्लभ हैं। दिमाग में आने वाला एकमात्र उदाहरण 'सशर्त वाईकटेबल' है, जो एक शब्दकोश की तरह है, लेकिन वस्तुओं को हटाने की अनुमति नहीं देता है। – supercat

4

जैसा कि पहले से ही अन्य पोस्टों द्वारा समझाया गया है, डिफ़ॉल्ट रूप से Queue या ConcurrentQueue से आइटम को निकालना संभव नहीं है, लेकिन वास्तव में आइटम को विस्तारित या लपेटना सबसे आसान तरीका है।

public class QueueItem 
{ 
    public Boolean IsRemoved { get; private set; } 
    public void Remove() { IsRemoved = true; } 
} 

और जब dequeuing:

QueueItem item = _Queue.Dequeue(); // Or TryDequeue if you use a concurrent dictionary 
if (!item.IsRemoved) 
{ 
    // Do work here 
} 
+0

यह समाधान स्मृति रिसाव का कारण बनता है। –

+0

@ किरीलबेस्टेमेनोव नहीं, यह स्मृति मेमोरी का कारण कैसे बनना चाहिए? –

+0

आप संग्रह से कार्य को हटा नहीं पाते हैं और इसलिए इस संग्रह द्वारा उपभोग की गई स्मृति केवल बढ़ने के कारण ही बढ़ी है। –

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