【问题标题】:Most efficient way to enumerate and modify over a ConcurrentBag of objects枚举和修改对象的 ConcurrentBag 的最有效方法
【发布时间】:2022-01-13 22:05:18
【问题描述】:

我有一个 ConcurrentBag 对象,我想对其进行以下操作:

  1. 使用 where 过滤枚举所有项目。
  2. 为每个项目检查一些属性,并根据值进行一些方法调用。方法调用后,最好从包中取出物品。
  3. 修改一些属性的值并保存到包中。

所以基本上我需要以下内容:

   foreach (var item in myBag.Where(it => it.Property1 = true))
        {
            
            if (item.Property2 = true)
            {
                SomeMethodToReadTheItem(item);
                //it's better to remove this item from the bag here, but 
                //there is a permeance hit, then just leave it.
            }
            else
            {
                item.Property3=  "new value";
                //now how do I save the item back to the bag?
            }
            
        }

因为它应该以线程安全的方式完成。我知道对 ConcurrentBag 的枚举实际上是对真实包的“快照”,但是使用 where 子句过滤器怎么样?我应该做一个 ToList 以防止它形成一个新的“快照”吗? 此外,如果您想修改一个特定项目,您只需 bag.TryTake(out item)。但是既然我已经拿到了枚举中的item,是不是又要“拿”一次呢?

任何解释/评论/示例都会非常有用。

谢谢。

【问题讨论】:

  • ConcurrentBag<T> 不太可能是您尝试做的任何事情的最佳工具。该类表示一个无序的物品包,只支持一个一个地随机取出物品。您无法从此集合中删除特定项目。这是一个专门的集合,用于混合生产者-消费者场景,这在实践中极为罕见。
  • 该类在内部一致性方面是线程安全的,但是,由于它包含引用,因此不能保证不会在内部共享资源的情况下让自己陷入困境。在大多数情况下,除非您有相当具体的用例,否则使用锁在概念上更容易。还有西奥多所说的

标签: c# .net multithreading concurrency


【解决方案1】:

我将尝试回答您问题的特定部分而不涉及性能。

首先,Where 方法将IEnumerable<T> 作为它的第一个参数,并且它本身将遍历将调用GetEnumerator() 一次的可枚举,因此您将只拍摄底层ConcurrentBag 的快照。

其次,您的代码的线程安全性不是很清楚,您的其余代码中可能存在一些未指定的隐含保证。例如,您有一个ConcurrentBag,因此您的集合是线程安全的,但是您修改该集合中包含的项目而无需任何线程同步。如果有其他代码运行相同的方法或在另一个方法中同时读取/修改ConcurrentBag 中的项目,那么您可能会看到数据竞争。

请注意,如果您已经拥有对该项目的引用,则无需调用TryTake,因为它只会返回相同的引用。

【讨论】:

    【解决方案2】:

    我建议您只创建一个新列表,如果使用 WHERE 过滤器,请将其添加到此新列表中。 它看起来像这样:

    List<T> myNewList = new List<T>();
    foreach (var item in myBag.Where(it => it.Property1))
        {
            if (!item.Property2)
            {
                myNewList.Add(item);
            }            
        }
    

    注意“!”

    【讨论】:

    • 我不确定这增加或回答了多少,或者甚至与 OP 所拥有的不同。也许你可以解释为什么你认为这是解决方案
    猜你喜欢
    • 2018-03-29
    • 2014-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多