किसी समसामयिक <<> एकल, विशिष्ट वस्तु को कैसे हटाया जाए?


109

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

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

जवाबों:


89

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

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

आपके लिए दो विकल्प:

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

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

2
@ILIABROUDNO - आपको इसका उत्तर देना चाहिए! जब आप एक शब्दकोश की जरूरत नहीं है, तो एक कुंडली समवर्ती से बेहतर तो बहुत है
डेनिस

2
FYI करें, सिंक्रोनाइज़्डकॉलिनेशन .NET Core में उपलब्ध नहीं है। इस टिप्पणी की तिथि तक, System.Collections.Concurrent प्रकार .NET कोर आधारित कार्यान्वयन के लिए जाने का वर्तमान तरीका है।
मैथ्यू स्नाइडर

2
मुझे यकीन नहीं है कि .NET कोर का कौन सा संस्करण इस्तेमाल किया जा रहा है, लेकिन मैं .NET कोर 2.1 एसडीके पर आधारित एक परियोजना पर काम कर रहा हूं और सिंक्रोनाइज्ड कॉलेक्शन अभी कलेक्शन में उपलब्ध है। जेनरिक नेमस्पेस।
लुकास लेब्लांक

15

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

आप एक सेट चाहते हैं। आप समवर्ती छायांकन के साथ एक का अनुकरण कर सकते हैं। या एक हैशसेट जिसे आप लॉक से सुरक्षित रखते हैं।


8
कृपया विस्तार करें। आप अंतर्निहित समवर्ती में कुंजी के रूप में क्या उपयोग करेंगे?
डेनिस स्किडमोर

2
ठीक है, मुझे लगता है कि कुंजी उस वस्तु का प्रकार होगी जिसे आप संग्रहीत करने की कोशिश कर रहे हैं, और फिर मूल्य कुछ प्रकार का संग्रह होगा। HashSetजैसा कि वह वर्णन करता है कि "अनुकरण" होगा ।
मैथियास लिकेगार्ड लोरेनजेन

5

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

जैसा कि मार्क बायर्स ने कहा था , आप एक नया समवर्ती बैग बना सकते हैं जिसमें वह आइटम नहीं है जिसे आप हटाना चाहते हैं, लेकिन आपको लॉक का उपयोग करके कई थ्रेड हिट के खिलाफ इसे सुरक्षित करना होगा। यह एक लाइनर है:

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

यह काम करता है, और उस आत्मा से मेल खाता है जिसमें समवर्ती बैग को डिजाइन किया गया है।


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

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

4

मार्क इस बात में सही है कि कॉन्ट्रैक्डरबेल उस तरह से काम करेगा जिस तरह से आप चाहते हैं। यदि आप अभी भी एक समवर्ती का उपयोग करना चाहते हैं निम्नलिखित, कुशल मन नहीं है, आप वहाँ मिल जाएगा।

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);
}

3

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


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);
    }

}

ConcurrentBagएक अनियंत्रित संग्रह है, लेकिन आपका कोड उम्मीद करता है कि bag.TryTakeऔर bag.AddFIFO तरीके से काम करे। आपका कोड मानता है कि bagइसमें शामिल है item, यह तब तक लूप करता है जब तक यह अंदर नहीं मिल itemजाता bag। कोड केवल उत्तर हतोत्साहित करते हैं, आपको अपने समाधान की व्याख्या करनी चाहिए।
गदविद

-1

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

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);
        }
    }
}

यह विश्वास करना मुश्किल है कि यह काम कर सकता है क्योंकि आप स्थानीय चर में नए समवर्तीबाग बना रहे हैं, लेकिन मुझे यकीन नहीं है। कोई भी परीक्षा?
shtse8

3
नहीं, यह काम नहीं करता है। यह कैसे काम करना चाहिए, आप केवल एक नया संदर्भ बना रहे हैं। पुराना अभी भी पुरानी वस्तु की ओर इशारा कर रहा है .... अगर आप "रेफ" के साथ काम करते हैं तो यह काम करेगा
थॉमस क्रिस्टोफ़

-5
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;
}

-13

कैसा रहेगा:

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

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


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

3
"बैग = नया समवर्तीबाग (बैग। कहीं भी (x => x! = आइटम)) होना चाहिए"
atikot

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