使用.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