使用.NET 4中的新增ConcurrentBag<T>
,當只有TryTake()
和TryPeek()
可用時,如何從中刪除某個特定的對象?如何從ConcurrentBag <>中刪除單個特定對象?
我想用TryTake()
,然後只是增加了生成的對象回列表,如果我不想刪除它,但我覺得我可能會失去了一些東西。這是正確的方法嗎?
使用.NET 4中的新增ConcurrentBag<T>
,當只有TryTake()
和TryPeek()
可用時,如何從中刪除某個特定的對象?如何從ConcurrentBag <>中刪除單個特定對象?
我想用TryTake()
,然後只是增加了生成的對象回列表,如果我不想刪除它,但我覺得我可能會失去了一些東西。這是正確的方法嗎?
簡短的回答:你不能以簡單的方式做到這一點。
ConcurrentBag爲每個線程保留一個線程本地隊列,並且一旦自己的隊列變空,它只會查看其他線程的隊列。如果你刪除一個項目並放回去,那麼你刪除的下一個項目可能再次是同一個項目。不能保證反覆移除項目並放回項目將允許您迭代所有項目。你
兩種選擇:
正如你所提到的,TryTake()
是唯一的選擇。這也是MSDN的例子。反射器也沒有顯示其他隱藏的內部方法。
你不能。它的一個包,它並沒有訂購。當你把它放回去時,你會陷入無限循環。
你想要一套。你可以用ConcurrentDictionary來模擬一個。或者你用鎖來保護自己的HashSet。
時,這比kludgey ConcurrentDictionary更好。請擴展。你將使用什麼作爲底層ConcurrentDictionary中的鍵? – 2014-01-10 20:19:09
那麼,我認爲關鍵是你試圖存儲的對象的類型,然後這個值將是某種類型的集合。正如他所描述的,這將「模擬」一個「HashSet」。 – 2014-05-25 21:22:33
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;
}
的ConcurrentBag如何有效......是偉大的處理列表,您可以添加項目,並從枚舉許多線程,然後最終扔掉它,因爲它的名字是建議:)
As Mark Byers told,你可以重新建立一個新的並不包含你想刪除的項目,你不得不使用鎖來防止多線程命中。這是一行代碼:
myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));
這個工作,並符合ConcurrentBag的設計精神。
我覺得這個答案有誤導性。要清楚的是,這不會在所需的刪除操作中提供任何線程安全性。並且鎖定它有點違背了使用併發集合的目的。 – 2016-10-07 19:53:43
我同意。好了,爲了澄清一下,ConcurrentBag被設計爲在完成時填充,枚舉並丟棄整個內容。任何企圖 - 包括我 - 移除物品都將導致骯髒的黑客攻擊。至少我試圖提供一個答案,但最好的是使用更好的併發集合類,如ConcurrentDictionary。 – Larry 2016-10-07 20:01:30
標記正確,因爲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);
}
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單個項目,也可以從袋中取出產品清單
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);
}
}
}
SynchronizedCollection也可能是一個合適的替代品。 – 2016-10-07 19:59:24
@ILIABROUDNO - 你應該把它作爲答案!當你不需要字典 – Denis 2017-07-14 17:25:53