c# 性能优化技巧

来源:这里教程网 时间:2026-02-21 17:38:26 作者:

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

频繁的堆分配会触发 GC,尤其在高频调用路径(如游戏帧更新、网络包解析)中,

new List<t>()</t>
new StringBuilder()
放在循环内是典型性能雷区。

实操建议:

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

慎用 LINQ 方法链

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

实操建议:

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

减少装箱和拆箱

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

实操建议:

用泛型集合替代非泛型:
List<int></int>
而非
ArrayList
Dictionary<string int></string>
而非
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<t></t>
)更高效
避免在
async void
方法里做耗时工作;不要用
.Result
.Wait()
阻塞异步任务,易死锁
var stream = File.OpenRead("data.json");
// ✅ 正确:真正异步反序列化
var obj = await JsonSerializer.DeserializeAsync<MyData>(stream);
// ❌ 错误:同步读+阻塞式反序列化+额外线程调度
var bytes = await File.ReadAllBytesAsync("data.json");
var obj = JsonSerializer.Deserialize<MyData>(bytes); // 同步CPU密集操作
实际优化时,先用
dotnet-trace
或 Visual Studio Profiler 抓热点,再针对性改。很多“技巧”在低频逻辑里毫无意义,反而让代码难懂。

相关推荐