【问题标题】:How to remove all Items from ConcurrentBag?如何从 ConcurrentBag 中删除所有项目?
【发布时间】:2011-07-19 15:16:57
【问题描述】:

如何清除ConcurrentBag?它没有像ClearRemoveAll 这样的方法...

【问题讨论】:

标签: c# concurrency


【解决方案1】:
int cnt = _queue.Count;
for (; cnt > 0; cnt--)
{
     _queue.TryDequeue(out img);
}

不会陷入死循环,会清除当前时间的内容。

【讨论】:

    【解决方案2】:

    从 .NET Core 2.0 / .NET Standard 2.1 / .NET Framework 5.0 开始,ConcurrentBag<T> 上有一个 Clear() 方法。请参阅:ConcurrentBag.Clear

    【讨论】:

      【解决方案3】:

      尽管由于潜在的竞争条件可能无法完全清除,但这已经足够了:

      while (!myBag.IsEmpty) 
      {
         myBag.TryTake(out T _);
      }
      

      【讨论】:

      • 这绝对不是原子的。所以我猜不应该作为扩​​展方法添加到 ConcurrentBag 上,因为所有其他方法都是在假设原子访问的情况下使用的。
      • 另外,TryTake 不会因为空的原因而失败吗?
      • 这很危险。如果另一个进程不断添加项目,这可能会保持忙碌。
      • @Adam Houldsworth 的回答 + 我的评论更好。
      • 如果这是一个危险的解决方案,为什么它仍然被接受?
      【解决方案4】:

      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而不受惩罚?
      • @ChrisMarisic 是的,如果您可以完全避免共享数据,那么您就不会遇到这些问题。然而,这个问题没有太多的背景。
      • Interlocked.Exchange 可能比锁好
      • 如果在交换时另一个线程正在添加到包中,Interlocked.Exchange 如何工作? AddExchange 期间是否被锁定?
      • 分配在 .NET 中是原子的,锁和 Interlocked.Exchange 在这里都是多余的(并且不提供线程安全)。
      【解决方案5】:

      本着变通办法的精神..ConcurrentDictionary&lt;T, bool&gt; 具有原子清除,但也允许您快速检查密钥是否存在。 “快速”当然是一个相对术语,但根据您的使用情况,它可能比枚举大堆栈更快。

      【讨论】:

      • 不错的一个!这应该被视为为此类实例选择的容器类型。 ConcurrentStack 类似。
      【解决方案6】:

      选择的答案是一种解决方法,所以我添加了我自己的解决方法。

      我的解决方案是查看System.Collections.Concurrent 命名空间中的所有可用集合,找到一个可以轻松清除集合中所有元素的集合。

      ConcurrentStack 类有一个Clear() 方法,可以从集合中删除所有元素。事实上,它是命名空间(当前)中唯一这样做的集合。是的,您必须使用Push(T element) 而不是Add(T element),但坦率地说,这值得节省时间。

      【讨论】:

      • 他的系列之间还有很多其他重要的区别。例如,如果您需要确定给定项目是否在集合中,使用 Bag 既简单又高效,但使用 Stack 则不然。
      • @Servy:是的,但仍然如此。不,实际上,我确实开始编写赞成/反对清单,但这实际上取决于您的要求。例如,并发集合适用于多线程访问,但它们都不允许您对集合进行索引,这可能会阻止您使用它们。问题特别是关于清除并发包(这就是我遇到它的原因),并且我的要求是用线程安全来简单地清除集合。我的回答是切换收藏。
      • 我也使用并发堆栈而不是包。奇怪的是 stack 有 Clear 和 Bag 没有。 bag 的主要目的是存储值,检查存在和删除全部或单个。所以并发栈就变成了类似于“有点受限的真正并发包”的东西。
      • @Servy 如何有效地确定给定项目是否包含在ConcurrentBag 中?我看不到任何本机属性或方法。 Contains 不算。它是泛型IEnumerables 的扩展方法,但效率不高。
      猜你喜欢
      • 2014-06-09
      • 1970-01-01
      • 1970-01-01
      • 2014-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      相关资源
      最近更新 更多