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