如何从ConcurrentBag <>中删除一个特定的对象?
使用.NET 4中新的ConcurrentBag<T>
,当只有TryTake()
和TryPeek()
可用时,如何从中删除某个特定的对象?
我想使用TryTake()
,然后只是添加结果对象回到列表中,如果我不想删除它,但我觉得我可能会失去一些东西。 这是正确的方法吗?
简短的回答:你不能以简单的方式做到这一点。
ConcurrentBag为每个线程保留一个线程本地队列,一旦自己的队列变空,它只会查看其他线程的队列。 如果您删除一个项目并将其放回,则删除的下一个项目可能会再次是相同的项目。 不能保证重复删除项目并将其放回将允许您迭代所有项目。
你有两种select:
- 删除所有项目并记住它们,直到find想要删除的项目,然后将其他项目放回去。 请注意,如果两个线程尝试同时执行此操作,则会遇到问题。
- 使用更合适的数据结构,如ConcurrentDictionary 。
你不能。 它的一个包,它不是有序的。 当你把它放回去时,你会陷入无限循环。
你想要一个Set。 你可以用ConcurrentDictionary模拟一个。 或者你用锁来保护自己的HashSet。
正如你TryTake()
, TryTake()
是唯一的select。 这也是MSDN上的例子。 reflection器也没有显示其他隐藏的内部方法。
Mark是正确的,因为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); }
ConcurrentBag很好处理一个列表,你可以添加项目和从多个线程枚举,然后最终抛弃它,因为它的名字是build议:)
正如Mark Byers所说 ,你可以重新构build一个新的ConcurrentBag,它不包含你想要删除的项目,但是你必须使用一个锁来防止multithreading命中。 这是一个单行的:
myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));
这是有效的,符合ConcurrentBagdevise的精神。
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; }
怎么样:
bag.Where(x => x == item).Take(1);
它的作品,我不知道如何有效率…