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

大型Unity/C#游戏中泛型集合过滤的最优性能实现方案问询

三种遍历筛选方式的性能差异

不同运行时环境下三者性能差距差异较大,以下为工业界通用实测结果:

  • for循环:性能最高,无额外运行时开销,直接通过索引访问List元素,内存开销仅取决于业务逻辑本身是否需要存储结果,是高频核心逻辑的最优选择。
  • foreach循环:针对List<T>类型时,C#编译器会默认优化为和for循环一致的索引访问逻辑,性能与for循环几乎无差异,仅当遍历接口类型IEnumerable<T>时才会产生枚举器分配开销。
  • Linq:
    旧版.NET Framework/Unity旧Mono运行时环境下,Linq执行效率比手写循环慢2~10倍,每次调用会产生几KB到几十KB的GC垃圾回收开销,主要来自委托实例、枚举器对象、ToList()生成的新列表分配,高频调用下会造成明显的帧卡顿。
    若使用Unity 2021+的.NET 6/7/8新版运行时,.NET官方针对Linq做了大量针对性优化,针对List<T>、数组等常用集合的重载性能比旧版提升3~5倍,简单筛选场景下性能和手写循环差距可缩小到20%以内,但依然存在少量GC开销。
适配游戏场景的最优实现方案

根据调用频率和业务优先级选择不同方案即可平衡性能与开发效率:

  1. 逐帧执行的高频核心逻辑(比如单位AI调度、碰撞检测筛选、帧级状态统计)
    优先使用for/foreach循环,禁止使用原生Linq。
    额外优化建议:不要每次筛选都生成新的结果列表,可缓存一个常驻的结果列表对象,每次筛选前调用Clear()再填充元素,完全避免列表内存分配开销。也可将常用筛选逻辑封装为无分配扩展方法,例:
    public static void FilterLowAmmoUnits(this List<Unit> source, List<Unit> output)
    {
        output.Clear();
        int threshold = Magazine.MaxCapacity * 3;
        for (int i = 0; i < source.Count; i++)
        {
            var unit = source[i];
            if (!unit.IsDead && !unit.IsCriticallyWounded && unit.AmmoCount < threshold)
            {
                output.Add(unit);
            }
        }
    }
    
  2. 事件触发、定时执行的非高频逻辑(比如UI统计显示、任务条件判断、单次事件响应)
    可直接使用Linq写法,提升代码可读性与可维护性,该场景下的性能开销完全可以忽略,除非单轮筛选的单位数量超过10万量级。
  3. 计数场景优化
    不要使用Where(cond).Count()的写法,优先手写for循环累加计数,或直接使用List<T>.Count(Func<T, bool>)重载,减少一次遍历开销。
  4. 超大量单位极端优化方案
    若单场战斗单位数量超过1万且存在大量多条件筛选需求,可采用空间换时间的预分组方案:维护对应筛选条件的缓存列表,当单位状态变更时(死亡、受伤、弹药变化、控制权变更),自动更新对应缓存列表的元素,需要使用时直接取缓存列表,完全无需遍历筛选,性能可提升数个数量级。
额外补充说明

如果项目暂时无法升级到新版Unity .NET运行时,又想保留Linq的简洁语法,可使用Unity社区开源的无GC Linq实现,这类库移除了原生Linq的内存分配逻辑,性能接近手写循环,可满足大部分场景需求。

内容的提问来源于stack exchange,提问作者Aaron Carter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:18:02