从代码到性能:20个硬核.NET优化技巧,避开90%开发者踩过的坑
我深耕.NET技术栈十余年,专注于C#代码优化,深知普通开发者与高性能工程师之间的差距往往源于对细节的把控。性能优化并非依赖最新硬件或盲目扩展,而是从编码之初就贯彻高效原则。
以下是20条性能优化技巧——既有常见实践,也有少为人知的秘技。它们将助你的.NET应用运行更快、内存消耗更低,展现真正的企业级表现。
1. 使用StringBuilder替代字符串拼接
反复使用+
或+=
拼接字符串是经典错误。C#字符串不可变,每次拼接都会创建新对象。改用StringBuilder
:
var sb = new StringBuilder();
for (int i = ; i < ; i++)
{
sb.Append("Hello ");
}
string result = sb.ToString();
此方法避免内存过度分配和垃圾回收压力。
2. 避免在性能关键路径中使用LINQ
LINQ虽提升可读性,但可能引入性能开销。例如:
代码语言:javascript代码运行次数:0运行复制var max = numbers.Max(); // 遍历集合两次!
改为简单循环:
代码语言:javascript代码运行次数:0运行复制int max = int.MinValue;
foreach (var num in numbers)
{
if (num > max) max = num;
}
大数据集下,此优化效果显著。
3. 固定大小时优先使用数组而非List
List<T>
虽灵活,但动态扩容有开销。已知元素数量时用数组:
int[] numbers = new int[]; // 消除扩容开销
4. 用Span和Memory处理大数据
操作大数组或字符串时,Span<T>
避免冗余内存分配:
Span<int> span = new int[] { , , , }; // 切片无需创建新数组
5. 减少装箱与拆箱操作
值类型与object
互转会触发堆分配。优先用泛型保持类型安全:
object obj = ; // 装箱 → 性能损失
int num = (int)obj; // 拆箱 → 性能损失
6. 对CPU密集型任务使用Parallel.For
并行任务利用多核优势:
代码语言:javascript代码运行次数:0运行复制Parallel.For(, , i => ProcessItem(i));
7. 在异步代码中使用ConfigureAwait(false)
无需返回UI线程时,始终添加:
代码语言:javascript代码运行次数:0运行复制await SomeAsyncMethod().ConfigureAwait(false); // 避免上下文切换
8. 若非事件处理器,避免async void
async void
难以处理异常。始终返回Task
:
async Task DoWorkAsync() { }
9. 用Dictionary<TKey, TValue>实现快速查找
字典的O(1)查找远胜列表遍历:
代码语言:javascript代码运行次数:0运行复制var dict = new Dictionary<int, string>();
dict[] = "First";
string value = dict[];
10. 用readonly struct定义不可变数据
readonly
结构体减少复制开销:
readonly struct Point { public int X { get; } public int Y { get; } }
11. 避免用异常处理控制流程
抛出异常代价高昂。勿用:
代码语言:javascript代码运行次数:0运行复制try { int value = dict[key]; } catch { }
改用:
代码语言:javascript代码运行次数:0运行复制if (dict.TryGetValue(key, out int value)) { }
12. 用Task.Run卸载后台任务
将计算密集型任务移至后台线程:
代码语言:javascript代码运行次数:0运行复制await Task.Run(() => ComputeHeavyTask());
13. 数据库连接启用连接池
在连接字符串中启用池化复用连接:
代码语言:javascript代码运行次数:0运行复制"Server=myServer;Database=myDB;User Id=myUser;Password=myPass;Pooling=true;"
14. 小数据模型优先用结构体
简单数据模型用结构体减少堆分配:
代码语言:javascript代码运行次数:0运行复制struct Employee { public int Id; public string Name; }
15. 小数组使用stackalloc栈内存分配
临时小数组直接在栈上分配:
代码语言:javascript代码运行次数:0运行复制Span<int> numbers = stackalloc int[];
16. 短生命周期线程使用线程池
避免新建线程,改用线程池:
代码语言:javascript代码运行次数:0运行复制ThreadPool.QueueUserWorkItem(_ => ProcessData());
17. 用GCSettings压缩大对象堆(LOH)
处理大对象时减少内存碎片:
代码语言:javascript代码运行次数:0运行复制GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
18. 延迟初始化高开销对象
用Lazy<T>
推迟昂贵操作:
private static readonly Lazy<MyService> _service = new(() => new MyService());
19. 用IAsyncEnumerable流式处理数据
大数据集异步逐条生成:
代码语言:javascript代码运行次数:0运行复制async IAsyncEnumerable<int> GetNumbers()
{
for (int i = ; i < ; i++)
yield return i;
}
20. 优化前先进行性能分析
勿盲目优化!用工具定位瓶颈:
- • PerfView
- • dotTrace
发布评论