C# 并行使用ConcurrentBag与简单阵列

C# 并行使用ConcurrentBag与简单阵列,c#,concurrency,parallel-processing,C#,Concurrency,Parallel Processing,这是一个假设性的问题/用例,基于(在本例中)在这个特定用例的并行for循环中通过简单数组使用ConcurrentBag的好处 该场景基于使用公共管道模式来分析从1到总结果的数字,根据其中一个管道操作的输出不为null来存储结果 结果列表的实际顺序很重要,因此使用一个简单的列表(类型为string)。add将根据每个线程何时决定返回结果而导致异常 我有以下工作代码: public IList<string> Execute(int total) { va

这是一个假设性的问题/用例,基于(在本例中)在这个特定用例的并行for循环中通过简单数组使用ConcurrentBag的好处

该场景基于使用公共管道模式来分析从1到总结果的数字,根据其中一个管道操作的输出不为null来存储结果

结果列表的实际顺序很重要,因此使用一个简单的列表(类型为string)。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();
    }
公共IList执行(整数总计)
{
var项目=新的ConcurrentBag();
Parallel.ForEach(迭代(1,(总计+1)),d=>
{
foreach(操作中的IOOperation操作)
{
var结果=操作。执行(d);
如果(结果!=null)
{
添加(新分析仪结果(d,结果));
打破
}
}
});
return items.OrderBy(o=>o.SortOrder).Select(d=>d.Result.ToList();
}
AnalyzerResult是一个简单的不可变类,代码只会将新项目推送到包中(因此理论上,项目列表中的某些内容不会发生更改)

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

    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();
    }
公共IList执行(整数总计)
{
var items=新字符串[总计];
Parallel.ForEach(迭代(1,(总计+1)),d=>
{
foreach(操作中的IOOperation操作)
{
var结果=操作。执行(d);
如果(结果!=null)
{
项目[(d-1)]=结果;
打破
}
}
});
return items.ToList();
}
注意:这不是并发问题,这两种方法都是合法的,都能产生预期的结果,没有问题。

我最初给出了一个“您需要并发保护”的答案,但随后重新阅读了问题的第二部分

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

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


照目前的情况,它应该很好,而且可读性很强。您可能希望对这段代码进行注释,说明您为什么这样做,以确保不会有人随意浏览它,并考虑“并发问题”(就像我刚才做的那样)和“修复”它。

因为您可以保证(通过对索引使用
d
)不会有两个线程同时访问数组的同一元素,我想这是安全的。并发类型的开销可能会降低其性能。我认为普通数组将是最快的合理实现。+1这也是我的观点,我确实想知道在这个阶段,是否有人会因为某种原因支持ConcurrentBag。是的,你的第三段总结了我的部分观点。我认为注释代码可能会转移问题的范围,但是添加了一个关于并发性的注释。很抱歉,我不清楚-我的意思是,如果您使用数组保留实际代码,那么您应该注释该代码,以便在您更改代码后维护代码的任何人都不会修改它。我不是说你需要在这里更新你的问题。明白了。当然,如果代码注释是真实世界中的问题,那么代码注释会有所帮助。