perf(util/gconv): Add gconv.Struct cache logic
- 对
gconv.Scan,gconv.Struct之类的函数(只要是转换到struct类型的)增加了缓存逻辑,不需要重复解析 - 对于常见类型的字段的转换使用
gconv.Int,gconv.String之类的,无需多次判断 - 缓存特性由
UseConvCacheExperiment函数来控制,默认开启,如果开启后有什么bug,关闭即可,平稳过渡 - 对于上次 #3412 的改进来说,性能方面大幅度提升,运行速度差不多有4倍,内存方面大幅度减少
- 对于需要模糊匹配的情况,增加一个字段来记上次找到的key,大概率可以不再需要模糊匹配
- 针对paramsMap的长度选择合适的方法来做赋值
- 如果paramsMap的长度比结构体的字段数量少,那么以paramsMap来做循环
- 反之用结构体字段map来做循环 这么所的原因是当paramsMap的长度和结构体字段数量差距过大时,会造成一些不必要浪费 比如 以下代码
type structType2 struct {
Name string
Score int
Age int
ID int
Name1 string
Score1 int
Age1 int
ID1 int
}
m := map[string]any{
"Name": "qiang",
"Score": 600,
"Age": 98,
"ID": 199,
}
如果采用结构体字段map的长度来做循环,那么至少需要循环len(结构体字段map)次,即时使用一个额外的字段来统计赋值次数,在合适的时机退出,也不能保证赋值4次就可以退出,因为map的无序性,可能前三个字段一开始就匹配好了,最后一个ID字段可能在第七次才匹配到,中间几次没有匹配到,依然需要模糊匹配,所以这里以paramsMap的长度来做循环比较好 另外一种情况也是同样的
以下是本次的性能,会有一些浮动,
最新提交的性能是
Benchmark_doStruct_Fields8_Basic_MapToStruct
Benchmark_doStruct_Fields8_Basic_MapToStruct-8 3223788 1882 ns/op 9 B/op 0 allocs/op
commit [26c14b3] 之前的
Benchmark_doStruct_Fields8_Basic_MapToStruct
Benchmark_doStruct_Fields8_Basic_MapToStruct-8 976039 6240 ns/op 1310 B/op 10 allocs/op
---
之前pr#3412的
Benchmark_Struct_my_Fields8_Basic_MapToStruct
Benchmark_Struct_my_Fields8_Basic_MapToStruct-8 482611 11708 ns/op 2074 B/op 44 allocs/op
Benchmark_Struct_gf_Fields8_Basic_MapToStruct
Benchmark_Struct_gf_Fields8_Basic_MapToStruct-8 214789 27090 ns/op 7668 B/op 138 allocs/op
@wln32 很棒的性能优化思路 👍 我刚粗略看了下,整体实现逻辑上没什么问题的,我需要仔细看看学习一下细节,需要花一点时间哈。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
@wln32 Great performance optimization idea 👍 I just took a quick look at it, and there is nothing wrong with the overall implementation logic. I need to take a closer look at the details and spend some time.
I'm still reviewing this. ❤️
Quality Gate passed
Issues
6 New issues
0 Accepted issues
Measures
0 Security Hotspots
0.0% Coverage on New Code
0.0% Duplication on New Code