You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组并行化疑问:线程安全与循环优化方案咨询

循环并行优化问题

我刚接触并行化概念,了解到存在线程风险。现有如下C#循环代码:

//OceanVertexIndexes 是 List<int> 类型
//trisWithVertex 是 List<int>[] 类型

foreach (int coord in terrainFace.OceanVertexIndexes)
    for (int j = 0; j < trisWithVertex[coord].Count; ++j)//遍历包含当前顶点的三角形
    {
         int value = trisWithVertex[coord][j];
         int remainder = value % 3;
         trianglesDisabled[value - remainder] = true;
         trianglesDisabled[value - remainder + 1] = true;
         trianglesDisabled[value - remainder + 2] = true;
     }

其中OceanVertexIndexes是包含数百到数千元素的枚举集合,trianglesDisabled可能被多线程同时访问。请问:

  • 这段循环能否进行并行优化?
  • 若可以,采用拆分循环为两半调用Parallel.Invoke,还是用Parallel.ForEach遍历的方式更合适?

备选代码如下:

//要不要这么做?
Parallel.Invoke(/*()=>处理OceanVertexIndexes的前半部分, ()=>处理后半部分*/);

//还是这么做?
Parallel.ForEach(terrainFace.OceanVertexIndexes, coord =>
{
    for (int j = 0; j < trisWithVertex[coord].Count; ++j)
    {
        int value = trisWithVertex[coord][j];
        int remainder = value % 3;
        trianglesDisabled[value - remainder] = true;
        trianglesDisabled[value - remainder + 1] = true;
        trianglesDisabled[value - remainder + 2] = true;
    }
});

解答

1. 可以进行并行优化,但需注意内存可见性

这段代码的核心操作是给trianglesDisabled数组的元素赋值为true,不存在“读-改-写”的竞态条件(无论线程执行顺序如何,最终结果都是true)。不过从.NET内存模型的严谨性出发,建议使用Volatile.Write来确保修改对其他线程可见,避免因CPU缓存导致的不可见问题:

Volatile.Write(ref trianglesDisabled[value - remainder], true);
Volatile.Write(ref trianglesDisabled[value - remainder + 1], true);
Volatile.Write(ref trianglesDisabled[value - remainder + 2], true);

如果是x86/x64架构,bool赋值本身是原子操作,不做这个处理大概率也能正常运行,但加上会更稳妥。

2. 优先选择Parallel.ForEach,放弃手动拆分的Parallel.Invoke

原因如下:

  • 自动负载均衡:Parallel.ForEach会根据CPU核心数量、任务的实际负载自动分配线程和元素,不需要你手动拆分集合,代码更简洁,维护成本更低。
  • 扩展性更好:如果后续OceanVertexIndexes的元素数量变化,或者CPU核心数增加,Parallel.ForEach能自动适应,而手动拆分的Parallel.Invoke需要你重新调整拆分逻辑,否则会出现负载不均(比如元素数为奇数时两半元素数量不等),浪费CPU资源。
  • 代码更简洁:无需编写集合拆分的额外逻辑,直接复用现有枚举集合即可。

如果trisWithVertex中各个子列表的长度差异极大,导致默认的分区策略效率不高,可以考虑使用Partitioner.Create自定义分区,但对你当前数百到数千元素的场景来说,默认的Parallel.ForEach已经足够高效。

内容的提问来源于stack exchange,提问作者Stefan Carpeliuc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 05:35:06