what
|
b81faafd18
|
perf: 缓存 GetStruct 构造的 struct 类型
reflect.StructOf 即使命中 runtime 自己的类型缓存, 仍然要重新构造
[]StructField、算签名、加锁查表。实测 12 字段的 struct:
reflect.StructOf(相同字段, 已缓存) 2349 ns / 2549 B / 31 allocs
reflect.TypeOf(已知类型) 2.3 ns / 0 B / 0 allocs
相差三个数量级。而 fields 在资源构造之后不再变化, 相同的 extends 必然得到
同一个类型, 完全可以缓存复用。
GetStruct/GetSliceStruct 抽出共用的 structType(), 结果按 extends 缓存:
GetStruct() 1399 ns / 2352 B / 28 allocs -> 22.2 ns / 48 B / 1 alloc 63x
GetStruct(extends) 1673 ns / 3592 B / 31 allocs -> 47.1 ns / 176 B / 2 allocs 36x
GetSliceStruct() 1457 ns / 2376 B / 29 allocs -> 31.5 ns / 24 B / 1 alloc 46x
缓存用切片线性扫描而不是 map: 键是 []reflect.StructField, 要做 map key 得先
拼字符串, 那笔开销反而可能盖过 StructOf 本身; 而 extends 的取值组合来自关联
配置, 数量很少, 逐项比对最省。条目数设了上限, 超出后退回每次现算, 保证内存有界。
一个容易踩的坑: 缓存键会复制一份再存。调用方常把 extends 当临时缓冲区复用
(append 到同一个底层数组上), 直接持有会让键在之后被改写, 变成命中错误类型的
隐蔽 bug。TestGetStructExtendsAliasing 专门守这个。
行为不变: GetStruct 仍然每次返回新实例, 只是复用类型。
新增 4 个测试(类型稳定性/extends 隔离/别名安全/并发)与 3 个基准。
|
2026-08-28 19:50:54 +08:00 |
|