在.NET 4中,使用新的ConcurrentBag<T>
,当只有TryTake()
和TryPeek()
可用时,如何从中删除特定的对象?
我考虑使用TryTake()
,如果我不想删除它,就将其添加回列表中,但我觉得我可能遗漏了什么。这是正确的方法吗?
在.NET 4中,使用新的ConcurrentBag<T>
,当只有TryTake()
和TryPeek()
可用时,如何从中删除特定的对象?
我考虑使用TryTake()
,如果我不想删除它,就将其添加回列表中,但我觉得我可能遗漏了什么。这是正确的方法吗?
简而言之:没有简便的方法可以做到。
ConcurrentBag为每个线程保留了一个本地队列,只有在自己的队列为空时才会查看其他线程的队列。如果您移除并重新放置一个项目,则下一个要移除的项目可能仍然是同一个项目。不能保证重复删除项目并将其放回会使您能够遍历所有项目。
以下是两种替代方案:
List<T>
。因此,移除操作的时间复杂度为O(n)。 - Oliver Bock你做不到。这是一个“袋子”,它没有顺序。当你把它放回去时,你只会陷入无限循环。
你需要一个集合(Set)。你可以用ConcurrentDictionary模拟一个集合,或者使用带锁的HashSet来保护自己。
HashSet
。 - Mathias Lykkegaard LorenzenConcurrentBag非常适合处理列表,您可以从多个线程添加项目并枚举,最终根据其名称的建议扔掉它 :)
正如Mark Byers所说,您可以重新构建一个不包含要删除项的新ConcurrentBag,但必须使用锁来保护它以防止多个线程同时操作。这是一行代码:
myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));
这个方法是有效的,并符合ConcurrentBag的设计理念。
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);
}
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.Add
按照FIFO的方式工作。
你的代码假设bag
包含item
,并且它会循环直到在bag
中找到item
。
仅提供代码答案是不鼓励的,你应该解释你的解决方案。 - GDavid这是我在项目中使用的扩展类。它可以从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);
}
}
}
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);
它可以工作,但我不确定效率如何...