【发布时间】:2011-07-19 15:16:57
【问题描述】:
如何清除ConcurrentBag?它没有像Clear 或RemoveAll 这样的方法...
【问题讨论】:
标签: c# concurrency
如何清除ConcurrentBag?它没有像Clear 或RemoveAll 这样的方法...
【问题讨论】:
标签: c# concurrency
int cnt = _queue.Count;
for (; cnt > 0; cnt--)
{
_queue.TryDequeue(out img);
}
不会陷入死循环,会清除当前时间的内容。
【讨论】:
从 .NET Core 2.0 / .NET Standard 2.1 / .NET Framework 5.0 开始,ConcurrentBag<T> 上有一个 Clear() 方法。请参阅:ConcurrentBag.Clear。
【讨论】:
尽管由于潜在的竞争条件可能无法完全清除,但这已经足够了:
while (!myBag.IsEmpty)
{
myBag.TryTake(out T _);
}
【讨论】:
2017 年 10 月 3 日更新: 正如@Lou 正确指出的那样,赋值是原子的。在这种情况下,ConcurrentBag 的创建将不是原子的,但将该引用放入变量 将是原子的 - 所以锁定或围绕它的 Interlocked.Exchange 并不是严格要求的。
进一步阅读:
reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?
Is a reference assignment threadsafe?
您始终可以锁定对包本身的访问并创建它的新实例。如果没有其他东西持有它们,那么袋子中的物品将符合 GC 条件:
lock (something)
{
bag = new ConcurrentBag();
}
或者正如 Lukazoid 指出的那样:
var newBag = new ConcurrentBag();
Interlocked.Exchange<ConcurrentBag>(ref bag, newBag);
但是,对内容进行分箱的简单方法是,它假定每当一个项目想要访问它时,它也会获得锁定 - 这可能会很昂贵,并且可能会抵消已进入 ConcurrentBag 本身的性能调整。
如果您知道此时没有其他东西可以访问该袋子,请边祈祷边祈祷,不要锁定 :-)
【讨论】:
bag = new而不受惩罚?
Interlocked.Exchange 可能比锁好
Interlocked.Exchange 如何工作? Add 在Exchange 期间是否被锁定?
Interlocked.Exchange 在这里都是多余的(并且不提供线程安全)。
本着变通办法的精神..ConcurrentDictionary<T, bool> 具有原子清除,但也允许您快速检查密钥是否存在。 “快速”当然是一个相对术语,但根据您的使用情况,它可能比枚举大堆栈更快。
【讨论】:
选择的答案是一种解决方法,所以我添加了我自己的解决方法。
我的解决方案是查看System.Collections.Concurrent 命名空间中的所有可用集合,找到一个可以轻松清除集合中所有元素的集合。
ConcurrentStack 类有一个Clear() 方法,可以从集合中删除所有元素。事实上,它是命名空间(当前)中唯一这样做的集合。是的,您必须使用Push(T element) 而不是Add(T element),但坦率地说,这值得节省时间。
【讨论】:
ConcurrentBag 中?我看不到任何本机属性或方法。 Contains 不算。它是泛型IEnumerables 的扩展方法,但效率不高。