如何清空 ConcurrentBag
?它没有像 Clear
或 RemoveAll
这样的方法...
如何清空 ConcurrentBag
?它没有像 Clear
或 RemoveAll
这样的方法...
更新于2017年10月3日:正如@Lou所正确指出的,赋值操作是原子性的。在这种情况下,创建ConcurrentBag
将不是原子性的,但将该引用放入变量中将是原子性的,因此不严格需要在其周围加锁或使用Interlocked.Exchange
。
进一步阅读:
引用赋值是原子性的,那么为什么需要Interlocked.Exchange(ref Object, Object)?
您可以始终锁定对包本身的访问并创建其新实例。如果没有其他东西持有它们,那么包中的项目将有资格进行垃圾收集:
lock (something)
{
bag = new ConcurrentBag();
}
正如Lukazoid所指出的:
var newBag = new ConcurrentBag();
Interlocked.Exchange<ConcurrentBag>(ref bag, newBag);
简单地分组内容,不过这假设每当一个项想要访问它时也会获得锁定,这可能很昂贵,可能会抵消已经投入到 ConcurrentBag
中的性能调整。
如果您知道此时没有其他内容将访问该包,则可以盲目尝试而不锁定 :-)
Interlocked.Exchange
都是多余的(并且不提供线程安全)。 - LouConcurrentBag
构造函数正在改变共享状态,那么这将是任何构造函数的代码异味。移除同步将为您提供更好的吞吐量,即减少争用,因此,如果GC立即收集第二个实例,则无关紧要。在两种情况下,您都无法控制不同的线程是否正在向新集合添加项目,或者已经将其添加到以前的集合中。 - Lou尽管由于潜在的竞态条件可能不完全清除,但这已经足够了:
while (!myBag.IsEmpty)
{
myBag.TryTake(out T _);
}
Push(T element)
而不是Add(T element)
,但坦率地说,这值得节省的时间。Contains
不算。它是通用IEnumerable
的扩展方法,而且一点也不高效。 - Theodor ZouliasConcurrentBag<T>
上有一个Clear()
方法。请参见:ConcurrentBag.Clear。在解决问题的精神下... ConcurrentDictionary<T, bool>
具有原子清除功能,同时允许您快速检查键是否存在。当然,“快速”是一个相对的术语,但根据您的使用情况,它可能比枚举大型堆栈要快。
嗯,我总是认为让底层框架去做工作更好。我只需将逻辑封装在一个专用函数中,在函数调用后,所有本地变量都会在GC感觉必要时自动丢弃。
void MyMainFunction(){
DoWorkWithTheBag();
}
void DoWorkWithTheBag(){
var newBag = new ConcurrentBag();
.....
}
int cnt = _queue.Count;
for (; cnt > 0; cnt--)
{
_queue.TryDequeue(out img);
}
它不会陷入无限循环,并清除当前时间的内容。