c# 性能优化技巧

7次阅读

性能优化应避免循环内创建对象、慎用linq、减少装箱拆箱、区分I/O与CPU密集型异步操作,并优先使用分析工具定位真实热点

c# 性能优化技巧

避免在循环里反复创建对象

频繁的分配会触发 GC,尤其在高频调用路径(如游戏帧更新、网络包解析)中,new List()new StringBuilder() 放在循环内是典型性能雷区。

实操建议:

  • 把对象声明提到循环外,复用实例(注意线程安全——若非并发场景,直接复用;若多线程,考虑 ThreadLocal 或对象池)
  • 对短生命周期字符串拼接,优先用 string.Concat()string.Join(),而非循环中 +=
  • Span 替代 ArraySegment 或临时数组,避免堆分配(例如解析字节流时用 Span.Slice()

慎用 LINQ 方法链

Where().select().ToList() 看起来简洁,但每层都生成新迭代器 + 多次遍历 + 额外装箱(对值类型),在热路径中开销明显。

实操建议:

  • 简单过滤/映射直接写 for 循环:索引访问快、无委托调用开销、无状态机生成
  • 必须用 LINQ 时,优先选 AsEnumerable() 前的原生集合方法(如 List.FindAll().ConvertAll()),它们是泛型实现,无装箱
  • count() 别用于已知长度的集合——直接用 .Count 属性;Any()Count() > 0 快得多

减少装箱和拆箱

intDateTime 等值类型调用 Object.ToString()、存入 ArrayList 或传给接受 object 的旧 API,都会触发装箱——分配堆内存并拷贝值。

实操建议:

  • 用泛型集合替代非泛型:List 而非 ArrayListDictionary 而非 Hashtable
  • 日志或调试输出时,避免隐式装箱:用 $"Value: {i}"(编译为 string.format 重载)比 "Value: " + i 更优(后者触发 i.ToString() 装箱)
  • 自定义结构体上别轻易加虚方法或实现接口(除非必要),否则传参/赋值可能隐式装箱

异步 I/O 不要盲目用 Task.Run

把同步文件读取、jsON 解析等 CPU 密集操作包进 Task.Run(() => {...}),看似“异步”,实则只是把线程池线程占住,还增加调度开销,对吞吐无益反损。

实操建议:

  • I/O 密集操作(http 请求、数据库查询、文件读写)优先用真正的异步方法:HttpClient.GetAsync()Filestream.ReadAsync()jsonSerializer.DeserializeAsync()
  • CPU 密集任务(图像处理、加密计算)才考虑 Task.Run,且需评估是否真需要并行——有时单线程 SIMD 指令(如 Vector)更高效
  • 避免在 async void 方法里做耗时工作;不要用 .Result.Wait() 阻塞异步任务,易死锁
var stream = File.OpenRead("data.json"); // ✅ 正确:真正异步反序列化 var obj = await JsonSerializer.DeserializeAsync(stream);  // ❌ 错误:同步读+阻塞式反序列化+额外线程调度 var bytes = await File.ReadAllBytesAsync("data.json"); var obj = JsonSerializer.Deserialize(bytes); // 同步CPU密集操作

实际优化时,先用 dotnet-tracevisual studio Profiler 抓热点,再针对性改。很多“技巧”在低频逻辑里毫无意义,反而让代码难懂。

text=ZqhQzanResources