.NET 8 搜索优化:SearchValues 和 FrozenCollections 加速热路径
.NET 8 新增了 SearchValues<T> 以及 FrozenSet<T>/FrozenDictionary<TKey, TValue> 等集合类型,它们大幅降低热路径开销。这些结构在创建时完成繁重计算,提供常量时间查找,无需重复分析。非常适合处理数百万操作的高吞吐量应用。
用 SearchValues 加速字符搜索
传统的 string.IndexOfAny 每次调用都会重新分析字符集,在循环中积累大量开销。SearchValues<char> 只需创建一次,就能缓存最优搜索策略。
初始化时,.NET 会执行:
- 输入集分析(单字符、范围或多字符)。
- 支持 SIMD(AVX2、SSE2)的算法选择。
- 构建数据结构(位掩码、哈希表)。
SearchValues<char> separators = SearchValues.Create(".,;!?");
ReadOnlySpan<char> input = "Hello, world!";
int index = input.IndexOfAny(separators);
搜索策略根据数据类型而变:
- 单字符 — 向量化检查。
- 范围(0-9A-Z) — O(1) 位掩码。
- 小集合(≤4 个字符) — SIMD。
- 大集合 — 优化的哈希表。
基准测试显示显著提升:
| 场景 | IndexOfAny | SearchValues | 加速比 |
|----------|------------|--------------|---------|
| 短字符串 | ~5 ns | ~5 ns | 1x |
| 长字符串(2000 字符) | ~52 ns | ~4 ns | ~13x |
对超过 100 字符的长字符串,收益最大,避免重复分析。
FrozenCollections:不可变哈希表
HashSet<T> 和 Dictionary<TKey, TValue> 带有变异开销,如重哈希和边界检查。FrozenSet<T> 和 FrozenDictionary<TKey, TValue> 专为只读场景优化。
创建时:
- 键分析,生成零冲突的完美哈希函数。
- 缓存友好的数据布局。
- 去除运行时不可变性检查。
小集合使用位掩码替代哈希。
var dict = Enumerable.Range(0, 100000)
.ToFrozenDictionary(x => x, x => $"Value {{x}}");
if (dict.TryGetValue(42, out string? value))
{
Console.WriteLine(value);
}
基准测试(10 万元素):
| 操作 | Dictionary | HashSet | FrozenDictionary | FrozenSet |
|-----------|------------|---------|------------------|-----------|
| TryGetValue/Contains | 3.78 ns | 4.47 ns | 1.87 ns | 3.37 ns |
FrozenDictionary 比标准 Dictionary 快一倍。
实际应用场景
SearchValues:
- 针对固定集的数百万次查找。
- 日志解析、分词、验证。
- 长字符串(>100 字符)。
FrozenCollections:
- 启动时加载的静态配置。
- 查找表(错误码、状态)。
- 读密集型工作负载,数千次查找。
频繁变异或罕见调用时避免使用——创建成本会抵消收益。
实用实现
在应用级别缓存:
public static class AppCache
{
public static readonly SearchValues<char> UrlSafeChars =
SearchValues.Create("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~");
public static readonly FrozenSet<string> ValidCurrencies =
new[] { "USD", "EUR", "GBP", "JPY", "CNY" }.ToFrozenSet();
}
验证示例:
- 邮箱:
SearchValues<char> invalidEmailChars = SearchValues.Create("()<>[]:;@\\,?\" "); - 顶级域名:
FrozenSet<string> validTlds = LoadTldsFromConfig().ToFrozenSet();
始终用 BenchmarkDotNet 性能分析——收益取决于操作量。
核心要点
SearchValues通过一次性优化,让长字符串搜索加速 13 倍。FrozenDictionary的TryGetValue性能是Dictionary的两倍。- 两者在热路径的不可变集上大放异彩。
- 先性能分析:不频繁调用无用。
- 利用 SIMD 和完美哈希,中高级开发者必备。
— Editorial Team
暂无评论。