-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf(util/gconv): Add gconv.Struct cache logic #3673
base: master
Are you sure you want to change the base?
Conversation
2.修改或新增一些注释 3.删除无用代码
2.对doStruct的params参数增加map[string]any的快速判断,减少内存申请次数
… Improve/cache-gconv-struct
2.模糊匹配时增加一个字段来记录最后一次匹配到的key,加快匹配
2.增加bool和[]byte两个常见类型的转换函数
… Improve/cache-gconv-struct
@wln32 很棒的性能优化思路 👍 我刚粗略看了下,整体实现逻辑上没什么问题的,我需要仔细看看学习一下细节,需要花一点时间哈。 |
@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. |
util/gconv/gconv_struct.go
Outdated
elemType = pointerElemReflectValue.Type() | ||
toBeConvertedFieldNameToInfoMap = map[string]toBeConvertedFieldInfo{} // key=elemFieldName | ||
// Indicates that those values have been used and cannot be reused. | ||
usedParamsKeyOrTagNameMap = poolGetUsedParamsKeyOrTagNameMap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个usedParamsKeyOrTagNameMap
恐怕不能使用pool
来全局复用吧,每个struct
转换的时候这个map
都应当是不一样的,复用的话恐怕会有问题哦?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个
usedParamsKeyOrTagNameMap
恐怕不能使用pool
来全局复用吧,每个struct
转换的时候这个map
都应当是不一样的,复用的话恐怕会有问题哦?!
@gqcn 可以的,没问题,每次用完吧map清空就行了,我注释那里有写的
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wln32 看了下你的代码,这个usedParamsKeyOrTagNameMap
是没有清空的就被defer
直接Put
进复用池了。如果采用了清空逻辑,这里的复用也没有意义了,不如新申请空的map
。
util/gconv/gconv_struct_cache.go
Outdated
convCacheExperiment = true | ||
) | ||
|
||
func UseConvCacheExperiment(b bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不建议把开关作为选项给使用者来控制,去掉该方法。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不建议把开关作为选项给使用者来控制,去掉该方法。
ok
util/gconv/gconv_struct_cache.go
Outdated
// For example: | ||
// if the type of the field is int, then directly cache the [gconv.Int] function | ||
convFunc func(from any, to reflect.Value) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个convertFieldInfoBase
结构的每一项属性描述请使用中文详细描述下作用。我来转为英文。
util/gconv/gconv_struct_cache.go
Outdated
// In this case, name shall prevail | ||
isField bool | ||
removeSymbolsFieldName string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个convertFieldInfo
结构的每一项属性描述请使用中文详细描述下作用。我来转为英文。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个
convertFieldInfo
结构的每一项属性描述请使用中文详细描述下作用。我来转为英文。
ok
util/gconv/gconv_struct_cache.go
Outdated
fieldNamesMap map[string]*convertFieldInfo | ||
} | ||
|
||
func (structInfo *convertStructInfo) NoFields() bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HasNoFields
util/gconv/gconv_struct_cache.go
Outdated
|
||
func (structInfo *convertStructInfo) GetFieldInfo(fieldName string) *convertFieldInfo { | ||
v := structInfo.fieldAndTagsMap[fieldName] | ||
return v |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return structInfo.fieldAndTagsMap[fieldName]
util/gconv/gconv_struct_cache.go
Outdated
structField reflect.StructField | ||
// Field index used to store duplicate names | ||
// Generally used for nested structures | ||
otherFieldIndex [][]int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么要定义多维数组?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么要定义多维数组?
正常是[]int,可以兼顾到嵌套的字段,使用[][]int的原因是嵌套的结构体字段可能会和外层结构体或者其他嵌套结构体的字段重名
例如以下
type Name struct{
LastName string
FirstName string
}
type User struct{
Name
LastName string
FirstName string
}
这种情况只会存储两个字段LastName
, FirstName
,使用不同的索引来代表不同的字段
2.把convertStructInfo.fieldNamesMap修改为slice,可以加快速度
util/gconv/gconv_struct.go
Outdated
elemType = pointerElemReflectValue.Type() | ||
toBeConvertedFieldNameToInfoMap = map[string]toBeConvertedFieldInfo{} // key=elemFieldName | ||
// Indicates that those values have been used and cannot be reused. | ||
usedParamsKeyOrTagNameMap = poolGetUsedParamsKeyOrTagNameMap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wln32 看了下你的代码,这个usedParamsKeyOrTagNameMap
是没有清空的就被defer
直接Put
进复用池了。如果采用了清空逻辑,这里的复用也没有意义了,不如新申请空的map
。
I'm still reviewing this. ❤️ |
…truct converting (#3) * fix(cmd/gf): fix command `gf up` with `-u` option upgrading packages indirectly required would fail with higher version of go required (gogf#3687) * up * up * refactor(util/gconv): add struct&field cache to improve performance for struct converting --------- Co-authored-by: 海亮 <739476267@qq.com>
|
gconv.Scan
,gconv.Struct
之类的函数(只要是转换到struct类型的)增加了缓存逻辑,不需要重复解析gconv.Int
,gconv.String
之类的,无需多次判断UseConvCacheExperiment
函数来控制,默认开启,如果开启后有什么bug,关闭即可,平稳过渡这么所的原因是当paramsMap的长度和结构体字段数量差距过大时,会造成一些不必要浪费
比如 以下代码
如果采用结构体字段map的长度来做循环,那么至少需要循环len(结构体字段map)次,即时使用一个额外的字段来统计赋值次数,在合适的时机退出,也不能保证赋值4次就可以退出,因为map的无序性,可能前三个字段一开始就匹配好了,最后一个ID字段可能在第七次才匹配到,中间几次没有匹配到,依然需要模糊匹配,所以这里以paramsMap的长度来做循环比较好
另外一种情况也是同样的
以下是本次的性能,会有一些浮动,