使用.NET 4中的新ConcurrentBag<T>
,当只有TryTake()
和TryPeek()
可用时,如何从中删除某个特定对象?
我正在考虑使用TryTake()
然后只是将结果对象添加回列表中,如果我不想要删除它,但我觉得我可能会丢失一些东西。这是正确的方法吗?
答案 0 :(得分:77)
简短的回答:你不能轻易地做到这一点。
ConcurrentBag为每个线程保留一个线程本地队列,并且只有在其自己的队列变空时才查看其他线程的队列。如果您删除了一个项目并将其放回原来,那么您删除的下一个项目可能会再次成为同一个项目。无法保证重复删除项目并将其放回将允许您迭代所有项目。
两种替代方案:
答案 1 :(得分:15)
你做不到。它是一个袋子,它没有订购。当你把它放回去时,你将陷入无休止的循环中。
你想要一套。您可以使用ConcurrentDictionary模拟一个。或者是一个用锁来保护自己的HashSet。
答案 2 :(得分:4)
ConcurrentBag非常适合处理List,你可以在其中添加项目并从多个线程枚举,然后最终将其丢弃,因为它的名字暗示:)
As Mark Byers told,您可以重新构建一个不包含您要删除的项目的新ConcurrentBag,但是您必须使用锁来防止多个线程命中。这是一个单行:
myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));
这很有效,并且符合ConcurrentBag的设计精神。
答案 3 :(得分:3)
正如您所提到的,TryTake()
是唯一的选择。这也是MSDN上的示例。反射器也没有显示其他隐藏的内部感兴趣的方法。
答案 4 :(得分:3)
马克是正确的,因为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);
}
答案 5 :(得分: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);
}
}
答案 6 :(得分:0)
改为尝试BlockingCollection<T>
。在.Net Core中可用。
答案 7 :(得分:-1)
这是我在我的项目中使用的扩展类。它可以从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);
}
}
}
答案 8 :(得分:-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;
}
答案 9 :(得分:-13)
怎么样:
bag.Where(x => x == item).Take(1);
它有效,我不确定效率如何......