C# C#性能

不用 unsafe,字符串处理也快四倍

日志解析服务有个热路径:每条日志按分隔符切成十几个字段,一天几千万条。原来的写法是一串 Split 加 Substring——功能没问题,但 GC 报表里 Gen0 分配速率常年飘红。

原因是 Substring 的语义:每切一次就在堆上新建一个字符串。一条日志切 12 刀 = 12 个新对象。改成 ReadOnlySpan<char> 之后,切片只是指针移动,不分配:

ReadOnlySpan<char> line = logLine.AsSpan();
int sep = line.IndexOf('|');
ReadOnlySpan<char> level = line.Slice(0, sep);          // 视图,不是副本
if (level.SequenceEqual("ERROR")) { ... }

改完压测:同样 100 万条日志,分配从 1.2 GB 降到 24 MB,耗时从 4.1 秒到 1.1 秒。全程没有 unsafe,没有指针算术,编译器保证内存安全——这是 Span 和裸指针的本质区别。

排查过程实录
排查过程实录

两条使用边界记一下:Span 只能待在栈上(不能存字段、不能跨 await),需要跨方法的用 Memory<T>;字符串比大小别用 ==(会把 Span 转回字符串),用 SequenceEqual。微软的分析器(CA1846 那些)会把不合规的写法标出来,开着就能逐步迁移。

不是所有字符串代码都值得改。高频热路径才值得,改之前先压测——但值得改的那些,收益常常出乎意料。