【问题标题】:Using a ConcurrentBag vs a simple Array in a Parallel for并行使用 ConcurrentBag 与简单数组
【发布时间】:2013-04-28 15:29:28
【问题描述】:

这是一个假设的问题/用例,基于在此特定用例的并行 for 循环中使用(在这种情况下)ConcurrentBag 而不是简单数组的好处。

该场景基于使用通用管道模式来分析从 1 到 total 结果的数字,并根据其中一个管道操作的输出存储 result,而不是为空。

结果列表的实际顺序很重要,因此使用简单的列表(字符串类型)。add 会根据每个线程决定返回结果的时间而产生奇怪的结果。

我有以下工作代码:

    public IList<string> Execute(int total)
    {
        var items = new ConcurrentBag<AnalyzerResult>();

        Parallel.ForEach(Iterate(1, (total + 1)), d =>
        {
            foreach (IOperation<T> operation in operations)
            {
                var result = operation.Execute(d);
                if (result != null)
                {
                    items.Add(new AnalyzerResult(d, result));
                    break;
                }
            }
        });

        return items.OrderBy(o=>o.SortOrder).Select(d => d.Result).ToList();
    }

AnalyzerResult 是一个简单的不可变类,并且代码只会将新项目推送到袋子中(因此理论上不会有 items 列表中的某些内容被更改的危险)。

基于此,一个简单的数组是否足够(并且包含更少的代码噪音)?或者使用并发类型会被认为是更好的实践/更高的性能?例如:

    public IList<string> Execute(int total)
    {
        var items = new string[total];

        Parallel.ForEach(Iterate(1, (total + 1)), d =>
        {
            foreach (IOperation<T> operation in operations)
            {
                var result = operation.Execute(d);
                if (result != null)
                {
                    items[(d - 1)] = result;
                    break;
                }
            }
        });

        return items.ToList();
    }

注意:这不是并发问题,这两种方法都是合法的,并且可以毫无问题地产生所需的结果。

【问题讨论】:

  • 由于您保证(通过使用d 作为索引)没有两个线程将同时访问数组的相同元素,我认为这将是安全的。并发类型的开销可能会使其性能降低。我认为普通数组将是最快的合理实现。
  • +1 这也是我的看法,我确实想知道在这个阶段是否有人会出于某种原因为 ConcurrentBag 辩护。

标签: c# concurrency parallel-processing


【解决方案1】:

我最初回答“您需要并发保护”,但后来重新阅读了您问题的第二部分。

这看起来应该可以工作,因为您不会尝试从两个不同的线程写入内存中的同一位置。因此,消除锁和线程关联(ConcurrentBag 提供的)应该会显着提高性能。

真正的问题是 - 增加了多少,是否需要增加(需要分析),您将来是否会更改此设置,以便您需要并发保护。

按原样,它应该没问题,而且可读性很强。您可能想要评论这段代码,说明您为什么这样做,以确保有人不会随便浏览它并认为“并发问题”(就像我刚才所做的那样)并“修复”它。

【讨论】:

  • 是的,你的第三段总结了我的部分观点。我认为评论代码可能会改变问题的范围,但添加了关于并发的注释。
  • 对不起,我不清楚 - 我的意思是如果您使用数组保留实际的真实代码,那么您应该注释该代码,以便在您之后维护代码的任何人都不会更改它。我并不是说你需要在你的问题中更新它。
  • 明白了。而且,是的,很自然,如果它是现实世界并且实际上是一个问题,代码 cmets 会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-30
相关资源
最近更新 更多