c# 程序调优与技巧

📅 发布时间:2026/7/16 11:53:47 👁️ 浏览次数:
c# 程序调优与技巧
**黄金法则**: 要么全同步,要么全异步,不要在调用链中间“截断”异步。---### 2. 并行处理:Parallel.ForEach 的合理使用适合 **CPU 密集型**、彼此独立的任务。csharpvar items = Enumerable.Range(1, 100).ToList();// ✅ 简单并行Parallel.ForEach(items, item ={var result = HeavyCompute(item);Console.WriteLine(result);});**调优点**:- 控制并发度,避免压垮 CPU # C# 程序性能调优与实战技巧(含可运行样例)本文面向有一定 C# 基础的开发者,聚焦**日常开发中高频、实用、可落地的调优手段**,覆盖集合、字符串、异步、内存、LINQ、Span 等关键场景,每个点都配有可直接运行的示例代码。---## 一、为什么“看起来没问题”的代码也需要调优?很多性能问题不是“能不能跑”,而是:- 高峰期 CPU 飙高- 内存占用缓慢上涨(疑似内存泄漏)- GC 频繁触发导致卡顿- 接口 P95 / P99 延迟不稳定调优的核心目标:**在保证可读性和可维护性的前提下,减少 CPU或下游 消耗、降低内存分配、减少 GC 压力**。---## 二、集合与字符串:最容易“悄悄”产生 GC 的地方### 1. 给集合预设容量,避免反复扩容`ListT` 默认初始容量为 `4`,满了之后会扩容为原来的 **2 倍**,并发生数组拷贝。csharp// ❌ 不推荐:频繁扩容var list = new Listint();for (int i = 0; i 10000; i++){list.Add(i);}// ✅ 推荐:一次性指定容量var list2 = new Listint(10000);for (int i = 0; i 10000; i++){list2.Add(i);}**适用场景**:- 循环前已知或能预估元素数量- ORM 查询结果、批量导入、缓存预热等同理适用于 `DictionaryK,V`、`HashSetT`、`StringBuilder`。---### 2. StringBuilder 的正确用法字符串是不可变的,频繁拼接会产生大量临时对象。csharp// ❌ 不推荐:循环中 + 拼接string s = "";for (int i = 0; i 10000; i++){s += i;}// ✅ 推荐:StringBuilder + 预设容量var sb = new StringBuilder(40000); // 预估长度for (int i = 0; i 10000; i++){sb.Append(i);}string result = sb.ToString();**经验值**:- 拼接次数 10 次,或总长度不可控 → 直接用 `StringBuilder`- Web API 返回 JSON 时,避免在业务逻辑层大量拼接字符串---## 三、异步与并发:避免“假异步”和线程浪费### 1. 服务:永远不要用 Task.Result/ .Wait()阻塞异步代码这会引发线程池饥饿甚至死锁(尤其在 ASP.NET 旧版本中)。// ❌ 不推荐:阻塞异步public int GetCount(){ return GetCountAsync().Result; // 危险!}// ✅ 推荐:一路 async/awaitpublic async Taskint GetCountAsync(){ var data = await httpClient.GetStringAsync("https://api.example.com/count"); return int.Parse(data);}黄金法则:要么全同步,要么全异步,不要在调用链中间“截断”异步。2. 并行处理:Parallel.ForEach 的合理使用适合 CPU 密集型、彼此独立的任务。var items = Enumerable.Range(1, 100).ToList();// ✅ 简单并行Parallel.ForEach(items, item ={ var result = HeavyCompute(item); Console.WriteLine(result);});调