【问题标题】:What is a real world use for ConcurrentBag<T>?ConcurrentBag<T> 的实际用途是什么?
【发布时间】:2011-09-20 19:06:27
【问题描述】:

ConcurrentBag 将允许多个线程从包中添加和删除项目。线程可能会将一个项目添加到包中,然后最终将相同的项目重新取出。它说 ConcurrentBag 是无序的,但它有多无序?在单个线程上,袋子就像一个堆栈。 unordered 是否意味着“不像链表”?

ConcurrentBag 的实际用途是什么?

【问题讨论】:

  • 你的意思是“它有多无序”?要么有定义的顺序,要么没有。这就像在说“猫王死了多少?”
  • 存储元素的排序与客户无关。所以从 API 的角度来看,“无序”总是指枚举的顺序(来自GetEnumerator 方法)。
  • “未订购”表示不保证订单。当前实现的行为似乎是,当同一个线程正在添加和删除时,它就像一个堆栈,当一个线程从另一个线程的集合中获取时,它就像一个队列。但我不会指望这种行为。有关更多信息,请参阅informit.com/guides/content.aspx?g=dotnet&seqNum=842。如果顺序不重要,并且线程既可以是生产者又可以是消费者,ConcurrentBag 可以提供比 ConcurrentQueue 更好的性能。

标签: .net-4.0 task-parallel-library


【解决方案1】:

包对于跟踪实例计数非常有用。例如,如果您想记录您正在为哪些主机提供 Web 请求服务,您可以在开始处理请求时将其 IP 添加到包中,并在完成后将其删除。

使用包可以让您一目了然地知道您当前正在服务哪些 IP。它还可以让您快速查询您是否在为给定的 IP 地址提供服务。

如果您为此使用集合而不是包,那么来自同一个 IP 地址的多个并发请求会弄乱您的记录保存。

【讨论】:

  • 您说将他们的 IP 添加到包中,然后在完成后将其删除。如何从包中取出特定物品?
  • @Dustin:好问题。当我写我的答案时,我想到了ConcurrentHashMultiset(Java 相当于ConcurrentBag),它确实有一个remove 方法。那么,我不知道 .NET ConcurrentBag 类有什么用处。 :-P
  • 没关系,根据您的回答,我能够想出一个适用于我自己的真实世界场景。
  • 这是一个线程安全哈希集的例子——可以使用底层的ConcurrentDictionary创建。
【解决方案2】:

您只需要跟踪那里的内容并且不需要随机访问或保证顺序的任何内容。如果您有一个添加要处理的项目的线程,以及一个删除项目以便处理它们的线程,那么如果您不关心它们是否按 FIFO 顺序处理,则并发包会很好地工作。

【讨论】:

    【解决方案3】:

    感谢@Chris Jester-Young,我想出了一个很好的真实世界场景,它实际上适用于我正在从事的项目。

    查找 - 处理 - 存储

    查找 - 线程 1 和 2 设置为查找或抓取数据(文件系统、网络等)。这些结果存储在 ConcurrentBag1 中。

    进程 - 线程 3 和 4 设置为从 ConcurrentBag1 中取出,清理/转换/处理数据,然后将结果存储在 ConcurrentBag2 中。

    Store - 线程 5 设置为从 ConcurrentBag2 收集结果并将结果存储在 SQL 中。

    【讨论】:

    • 从描述来看,这听起来使用分层队列(可能是ConcurrentQueueBlockingCollection 实例)而不是ConcurrentBag 类会更好。不过,类用法之间似乎有相当多的重叠,所以我可能弄错了。
    【解决方案4】:

    因为没有排序,所以 ConcurrentBag 比 ConcurrentStack/Queue 具有性能优势。它由 Microsoft 实现为本地线程存储。因此,每个添加项目的线程都在它自己的空间中执行此操作。检索项目时,它们来自本地存储。只有当它为空时,线程才会从另一个线程存储中窃取项目。因此,ConcurrentBag 不是一个简单的列表,而是一个分布式项目列表。并且几乎是无锁的,并且在高并发下应该可以更好地扩展。

    不幸的是,在 .NET 4.0 中存在性能问题(在 4.5 中已修复)请参阅 http://ayende.com/blog/156097/the-high-cost-of-concurrentbag-in-net-4-0

    【讨论】:

      猜你喜欢
      • 2011-04-02
      • 2019-05-17
      • 2015-04-22
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      相关资源
      最近更新 更多