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

为何Grasshopper中C#多线程点距离计算代码比单线程慢?

多线程计算点对距离反而更慢的原因及优化方案

你的代码之所以比单线程慢,核心问题不在于多线程本身,而是代码里的几个低效设计拖垮了性能,具体分析如下:

1. x.IndexOf(pt)带来的O(n²)级开销

在Parallel.ForEach的循环体里,你通过x.IndexOf(pt)获取当前点的索引,而List.IndexOf是线性查找(O(n)复杂度)。10000个点的情况下,总操作量变成了10000×10000=1亿次,这直接把计算复杂度从单线程的O(n)拉到了O(n²),这是性能暴跌的主要原因——和多线程无关,哪怕单线程这么写也会慢得离谱。

2. ConcurrentDictionary的不必要锁开销

你用ConcurrentDictionary存储结果,但实际上这里根本不需要线程安全的字典:因为两组点是一一对应的,每个计算任务只需要操作对应索引的位置,完全没有线程竞争。ConcurrentDictionary内部的锁机制会带来额外的性能损耗,完全是冗余的。

3. 轻量计算的多线程调度开销抵消收益

Point3d.DistanceTo是非常简单的数学运算(平方差求和开根号),属于超轻量任务。多线程的线程调度、上下文切换本身有一定开销,如果每个任务的计算量太小,这些开销会超过多线程带来的并行收益,导致整体速度比单线程还慢。


优化后的代码

针对以上问题,优化后的代码如下:

private void RunScript(List<Point3d> x, List<Point3d> y, ref object A)
{
    // 先校验两组点数量是否一致
    if (x.Count != y.Count)
    {
        A = null;
        return;
    }
    
    // 用数组存储结果,每个索引位置独立,无线程竞争
    double[] results = new double[x.Count];
    
    // 按索引并行循环,避免线性查找
    Parallel.For(0, x.Count, i =>
    {
        results[i] = x[i].DistanceTo(y[i]);
    });
    
    A = new List<double>(results);
}

优化说明

  • 改用索引循环:直接通过i访问对应位置的点,彻底消除IndexOf的O(n)开销,把复杂度拉回O(n)
  • 用普通数组代替ConcurrentDictionary:数组的每个索引位置由单个线程操作,不需要锁,消除线程安全容器的额外开销
  • 保留并行逻辑的同时,最大化降低额外损耗:如果后续你的计算任务变得更复杂(比如每个点需要做更多几何运算),这个并行方案会开始体现性能优势;但如果只是简单的距离计算,单线程可能依然是最优选择——因为轻量任务的并行收益抵不上调度开销。

内容的提问来源于stack exchange,提问作者Charles Boman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:40:22