2010-06-12 20 views
74

.NET 4 में नए ConcurrentBag<T> के साथ, आप केवल TryTake() और TryPeek() उपलब्ध होने पर एक निश्चित, विशिष्ट ऑब्जेक्ट को कैसे हटाते हैं?ConcurrentBag <> से एकल, विशिष्ट ऑब्जेक्ट को कैसे निकालें?

मैं TryTake() का उपयोग करने का सोच रहा हूँ और फिर बस सूची में वापस जिसके परिणामस्वरूप वस्तु जोड़ने अगर मैं नहीं इसे हटाने के लिए चाहते हैं, लेकिन मुझे लगता है कि मैं कुछ कमी हो सकती है। क्या यह सही तरीका है?

उत्तर

63

संक्षिप्त उत्तर: आप इसे एक आसान तरीके से नहीं कर सकते हैं।

ConcurrentBag प्रत्येक थ्रेड के लिए एक थ्रेड स्थानीय कतार रखता है और यह केवल अपनी धागा खाली होने के बाद अन्य धागे की कतारों को देखता है। यदि आप कोई आइटम हटाते हैं और उसे वापस डाल देते हैं तो आपके द्वारा निकाली जाने वाली अगली वस्तु एक ही आइटम हो सकती है। इस बात की कोई गारंटी नहीं है कि बार-बार वस्तुओं को हटाने और उन्हें वापस रखने से आप सभी वस्तुओं पर पुन: प्रयास कर सकेंगे। आप के लिए

दो विकल्प:

  • सभी आइटम निकालें और याद उन्हें, जब तक आप एक आप निकालना चाहते हैं लगता है, तो दूसरों को वापस रख बाद में। ध्यान दें कि यदि दो थ्रेड एक साथ ऐसा करने का प्रयास करते हैं तो आपको समस्याएं आती हैं।
  • ConcurrentDictionary जैसे अधिक उपयुक्त डेटा संरचना का उपयोग करें।
+2

SynchronizedCollection भी एक उपयुक्त विकल्प हो सकता है। –

+0

@ILIABROUDNO - आपको इसे उत्तर के रूप में रखना चाहिए! जब आपको डिक्शनरी – Denis

3

जैसा कि आप उल्लेख करते हैं, TryTake() एकमात्र विकल्प है। यह MSDN पर भी उदाहरण है। परावर्तक या तो ब्याज की कोई अन्य छुपी आंतरिक विधियां नहीं दिखाता है।

13

आप नहीं कर सकते। यह एक बैग है, यह आदेश नहीं दिया जाता है। जब आप इसे वापस रख देते हैं, तो आप बस एक अंतहीन पाश में फंस जाएंगे।

आप एक सेट चाहते हैं। आप ConcurrentDictionary के साथ एक अनुकरण कर सकते हैं। या एक हैशसेट है कि आप अपने आप को ताला से बचाते हैं।

+6

की आवश्यकता नहीं है, तो यह एक क्लुजी कंसुरेंट डिक्शनरी से बहुत बेहतर है। अंतर्निहित ConcurrentDictionary में कुंजी के रूप में आप क्या उपयोग करेंगे? –

+2

खैर, मुझे लगता है कि कुंजी उस ऑब्जेक्ट का प्रकार होगा जिसे आप स्टोर करने का प्रयास कर रहे हैं, और फिर मान कुछ प्रकार का संग्रह होगा। जैसा कि वह वर्णन करता है वह 'हैशसेट' को "अनुकरण" करेगा। –

-12

तरीके के बारे में:

bag.Where(x => x == item).Take(1); 

यह काम करता है, मुझे नहीं यकीन है कि कैसे कुशलतापूर्वक ...

+0

यह बैग से कुछ भी नहीं हटाता है। जिस आइटम को आप पुनर्प्राप्त कर रहे हैं वह बैग के अंदर बनी हुई है। – Keith

+3

"बैग = नया कंसूरेंटबैग होना चाहिए (बैग। जहां (x => x! = आइटम))" – atikot

+3

@atikot, उस पंक्ति ने मुझे हंस दिया – parek

-4
public static ConcurrentBag<String> RemoveItemFromConcurrentBag(ConcurrentBag<String> Array, String Item) 
{ 
    var Temp=new ConcurrentBag<String>(); 
    Parallel.ForEach(Array, Line => 
    { 
     if (Line != Item) Temp.Add(Line); 
    }); 
    return Temp; 
} 
1

ConcurrentBag एक सूची आप आइटम जोड़ने और से गणना कर सकते हैं जहां संभाल करने महान है कर रहा हूँ कई थ्रेड, फिर आखिरकार इसे फेंक दें क्योंकि इसका नाम सुझाव दे रहा है :)

As Mark Byers told, आप एक नया ConcurrentBag फिर से बना सकते हैं जिसमें उस आइटम को शामिल नहीं किया गया है जिसे आप निकालना चाहते हैं, bu आपको लॉक का उपयोग करके कई धागे हिट के खिलाफ इसे सुरक्षित रखना होगा। यह एक लाइनर है:

myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry })); 

यह काम करता है, और उस भावना से मेल खाता है जिसमें ConcurrentBag के लिए डिज़ाइन किया गया है।

+0

मुझे लगता है कि यह जवाब भ्रामक है। स्पष्ट होने के लिए, यह वांछित निकालें ऑपरेशन में कोई थ्रेड सुरक्षा प्रदान नहीं करता है। और इसके चारों ओर एक ताला लगाकर एक समवर्ती संग्रह का उपयोग करने के उद्देश्य को हरा देता है। –

+0

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

2

मार्क सही है कि ConcurrentDictionary इस तरह से काम करेगा जिस तरह आप काम कर रहे हैं। यदि आप अभी भी ConcurrentBag का उपयोग करना चाहते हैं, तो आपको कोई मज़ेदार दिमाग नहीं है, तो आप वहां पहुंच जाएंगे।

var stringToMatch = "test"; 
var temp = new List<string>(); 
var x = new ConcurrentBag<string>(); 
for (int i = 0; i < 10; i++) 
{ 
    x.Add(string.Format("adding{0}", i)); 
} 
string y; 
while (!x.IsEmpty) 
{ 
    x.TryTake(out y); 
    if(string.Equals(y, stringToMatch, StringComparison.CurrentCultureIgnoreCase)) 
    { 
     break; 
    } 
    temp.Add(y); 
} 
foreach (var item in temp) 
{ 
    x.Add(item); 
} 
1
public static void Remove<T>(this ConcurrentBag<T> bag, T item) 
{ 
    while (bag.Count > 0) 
    { 
     T result; 
     bag.TryTake(out result); 

     if (result.Equals(item)) 
     { 
      break; 
     } 

     bag.Add(result); 
    } 

} 
2

यह मेरा विस्तार वर्ग जो मैं अपनी परियोजनाओं में उपयोग कर रहा हूँ है। यह एक ConcurrentBag से एक आइटम को हटा सकते हैं और यह भी बैग से आइटम की सूची से हटा सकते हैं

public static class ConcurrentBag 
{ 
    static Object locker = new object(); 

    public static void Clear<T>(this ConcurrentBag<T> bag) 
    { 
     bag = new ConcurrentBag<T>(); 
    } 


    public static void Remove<T>(this ConcurrentBag<T> bag, List<T> itemlist) 
    { 
     try 
     { 
      lock (locker) 
      { 
       List<T> removelist = bag.ToList(); 

       Parallel.ForEach(itemlist, currentitem => { 
        removelist.Remove(currentitem); 
       }); 

       bag = new ConcurrentBag<T>(); 


       Parallel.ForEach(removelist, currentitem => 
       { 
        bag.Add(currentitem); 
       }); 
      } 

     } 
     catch (Exception ex) 
     { 
      Debug.WriteLine(ex.Message); 
     } 
    } 

    public static void Remove<T>(this ConcurrentBag<T> bag, T removeitem) 
    { 
     try 
     { 
      lock (locker) 
      { 
       List<T> removelist = bag.ToList(); 
       removelist.Remove(removeitem);     

       bag = new ConcurrentBag<T>(); 

       Parallel.ForEach(removelist, currentitem => 
       { 
        bag.Add(currentitem); 
       }); 
      } 

     } 
     catch (Exception ex) 
     { 
      Debug.WriteLine(ex.Message); 
     } 
    } 
} 
संबंधित मुद्दे