【问题标题】:Equivalent of Array in Concurrent Collections并发集合中数组的等价物
【发布时间】:2018-09-26 19:38:36
【问题描述】:

我在单线程环境中有以下流程:

int[] ages = { 40, 30, 18, 23, 60, 24 };
for (int i = 0; i < ages.Length; i++)
{
    if (ages[i] < 21) ages[i] = 0;
}

作为示例,但现在我想在 多线程环境 中执行此过程。 有没有并发集合在多线程环境下模拟数组?

【问题讨论】:

  • ConcurrentBag&lt;T&gt; 也许
  • 不完全是,ConcurrentBag 并不是为了保持索引顺序。但请注意,此代码可以并行化,而不会轻易与 ParallelFor 发生冲突。
  • ConcurrentBag 不允许按索引访问键,这是我想要归档的。

标签: c# concurrency task-parallel-library


【解决方案1】:

最接近的解决方案是使用 ConcurrentDictionary 使用索引作为键。在这种情况下,哈希函数会非常好:

var dict = new ConcurrentDictionary<int, int>(Enumerable.Range(0, ages.Length).ToDictionary(i => i, i => ages[i]));
Parallel.For(0, dict.Count,
    i =>
    {
        int value;
        if (dict.TryGetValue(i, out value) && value < 21)
            dict.TryUpdate(i, value, 0);
    });

请注意,这个特定示例根本不需要使用 ConcurrentDictionary,因为您在每次迭代之间没有依赖关系。

Parallel.For(0, ages.Length,
    i =>
    {
        if (ages[i] < 21) ages[i] = 0;
    });

此代码非常适合您的示例。下次使用更复杂的东西,比如数组元素的总和。

希望对您有所帮助!

【讨论】:

    【解决方案2】:

    您可以尝试使用Parallel Linq (PLinq) 并让.Net materialize 最终结果为数组;在你的情况下:

     int[] ages = { 40, 30, 18, 23, 60, 24 };
    
     ages = ages
       .AsParallel()
       .Select(age => age < 21 ? 0 : age)
       .ToArray(); 
    

    PLinq 的优点是 .Net 负责内部集合选择、锁定等。如果你想并行计算平均年龄,你所要做的就是稍微编辑查询:

     var averageAge = ages
       .AsParallel()
       .Average();
    

    【讨论】:

      猜你喜欢
      • 2010-11-13
      • 2012-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多