Answers:
简短的答案:您无法轻松实现。
ConcurrentBag为每个线程保留一个线程本地队列,并且仅在其自己的队列为空时才查看其他线程的队列。如果您删除一个项目并将其放回去,那么您删除的下一个项目可能又是同一项目。无法保证反复删除项目并将其放回原处将允许您遍历所有项目。
为您提供两种选择:
你不能 它是一个袋子,没有订购。当您放回原处时,只会陷入无休止的循环。
您想要一套。您可以使用ConcurrentDictionary模拟一个。或使用锁保护自己的HashSet。
HashSet
正如他所描述的那样,这将“模仿” a 。
ConcurrentBag非常适合处理List,您可以在其中添加项目并从许多线程中枚举,然后按其名称的建议最终将其丢弃:)
正如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);
}
如您所述,TryTake()
是唯一的选择。这也是MSDN上的示例。Reflector也没有显示其他任何隐藏的内部感兴趣的方法。
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
,它循环,直到找到item
在bag
。不鼓励仅使用代码的答案,您应该解释您的解决方案。
这是我在项目中使用的扩展类。它可以从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);
它有效,我不确定效率如何...