[Golang语言社区]--提高 golang 的反射性能

前端之家收集整理的这篇文章主要介绍了[Golang语言社区]--提高 golang 的反射性能前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
golang 的反射很慢。这个和它的 api 设计有关。在 java 里面,我们一般使用反射都是这样来弄的。@H_502_2@
Field field =@H_502_2@ clazz.@H_502_2@getField(@H_502_2@@H_502_2@"hello"@H_502_2@)@H_502_2@;@H_502_2@
field.@H_502_2@get(@H_502_2@@H_502_2@obj1)@H_502_2@;@H_502_2@
field.@H_502_2@(@H_502_2@@H_502_2@obj2)@H_502_2@;@H_502_2@
@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@

这个取得的反射对象类型是 java.lang.reflect.Field。它是可以复用的。只要传入不同的obj,就可以取得这个obj上对应的 field。但是 golang 的反射不是这样设计的

type_ :=@H_502_2@ reflect.@H_502_2@TypeOf(@H_502_2@@H_502_2@obj)@H_502_2@
field,@H_502_2@ _@H_502_2@ :=@H_502_2@ type_.@H_502_2@FieldByName"hello"@H_502_2@)@H_502_2@
@H_502_2@@H_502_2@@H_502_2@@H_502_2@

这里取出来的 field 对象是 reflect.StructField 类型,但是它没有办法用来取得对应对象上的值。如果要取值,得用另外一套对object,而不是type的反射

ValueOf(@H_502_2@@H_502_2@obj)@H_502_2@ fieldValue :=@H_502_2@ type_.@H_502_2@ 这里取出来的 fieldValue 类型是 reflect.Value,它是一个具体的值,而不是一个可复用的反射对象了。

这就很蛋疼了!每次反射都需要malloc这个reflect.Value结构体。golang的反射性能怎么可能快?

Jsoniter 是 golang 实现的,基于反射的 JSON 解析器。其实现原理是用 reflect.Type 得出来的信息来直接做反射,而不依赖于 reflect.ValueOf。具体是怎么实现的呢?

结构体

解决一个小问题。怎么利用 reflect.StructField 取得对象上的值?

对应的代码在:go/feature_reflect_object.go at master · json-iterator/go · GitHub

fieldPtr :=@H_502_2@ uintptr(@H_502_2@@H_502_2@structPtr)@H_502_2@ +@H_502_2@ field.@H_502_2@Offset @H_502_2@@H_502_2@@H_502_2@

在 reflect.StructField 上有一个 Offset 的属性。利用这个可以计算出字段的指针值。我们可以写一个小测试来验证,这个是对的。

type@H_502_2@ TestObj struct@H_502_2@ {@H_502_2@ field1 string@H_502_2@ }@H_502_2@ struct_ :=@H_502_2@ &@H_502_2@TestObj{@H_502_2@}@H_502_2@ field,255);">_@H_502_2@ :=@H_502_2@ reflect.@H_502_2@(@H_502_2@@H_502_2@struct_)@H_502_2@.@H_502_2@Elem(@H_502_2@@H_502_2@)@H_502_2@.@H_502_2@"field1"@H_502_2@)@H_502_2@ field1Ptr :=@H_502_2@ (@H_502_2@@H_502_2@unsafe.@H_502_2@Pointer(@H_502_2@@H_502_2@struct_)@H_502_2@)@H_502_2@ +@H_502_2@ field.@H_502_2@Offset *@H_502_2@(@H_502_2@(@H_502_2@*@H_502_2@string@H_502_2@)@H_502_2@(@H_502_2@unsafe.@H_502_2@(@H_502_2@@H_502_2@field1Ptr)@H_502_2@)@H_502_2@)@H_502_2@ =@H_502_2@ "hello"@H_502_2@ fmt.@H_502_2@Println(@H_502_2@@H_502_2@struct_)@H_502_2@ @H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@

打印出来的消息是 &{hello}

获取 interface{} 的指针

如果对应的结构体是以 interface{} 传进来的。还需要从 interface{} 上取得结构体的指针

string@H_502_2@ }@H_502_2@ struct_ :=@H_502_2@ &@H_502_2@TestObj{@H_502_2@}@H_502_2@ structInter :=@H_502_2@ (@H_502_2@interface@H_502_2@{@H_502_2@}@H_502_2@)@H_502_2@(@H_502_2@struct_)@H_502_2@ @H_404_292@// emptyInterface is the header for an interface{} value.@H_502_2@ type@H_502_2@ emptyInterface struct@H_502_2@ {@H_502_2@ typ *@H_502_2@struct@H_502_2@{@H_502_2@}@H_502_2@ word unsafe.@H_502_2@Pointer }@H_502_2@ structPtr :=@H_502_2@ (@H_502_2@*@H_502_2@emptyInterface)@H_502_2@(@H_502_2@unsafe.@H_502_2@(@H_502_2@@H_502_2@&@H_502_2@structInter)@H_502_2@)@H_502_2@.@H_502_2@word field,242);">(@H_502_2@@H_502_2@structInter)@H_502_2@.@H_502_2@(@H_502_2@@H_502_2@structPtr)@H_502_2@ +@H_502_2@ field.@H_502_2@Offset *@H_502_2@(@H_502_2@(@H_502_2@*@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@

Slice

搞定了结构体,接下来就是处理slice类型了。

对应的代码在:go/feature_reflect_array.go at master · json-iterator/go · GitHub

type@H_502_2@ sliceHeader struct@H_502_2@ {@H_502_2@ Data unsafe.@H_502_2@Pointer Len int@H_502_2@ Cap int@H_502_2@ }@H_502_2@ @H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@

slice 的秘诀在于取出指向数组头部的指针,然后具体的元素,通过偏移量来计算。

slice :=@H_502_2@ [@H_502_2@]@H_502_2@string@H_502_2@{@H_502_2@"hello"@H_502_2@,@H_502_2@ "world"@H_502_2@}@H_502_2@ int@H_502_2@ }@H_502_2@ header :=@H_502_2@ (@H_502_2@*@H_502_2@sliceHeader)@H_502_2@(@H_502_2@unsafe.@H_502_2@(@H_502_2@@H_502_2@&@H_502_2@slice)@H_502_2@)@H_502_2@ fmt.@H_502_2@(@H_502_2@@H_502_2@header.@H_502_2@Len)@H_502_2@ elementType :=@H_502_2@ reflect.@H_502_2@(@H_502_2@@H_502_2@slice)@H_502_2@.@H_502_2@(@H_502_2@@H_502_2@)@H_502_2@ secondElementPtr :=@H_502_2@ (@H_502_2@@H_502_2@header.@H_502_2@Data)@H_502_2@ +@H_502_2@ elementType.@H_502_2@Size(@H_502_2@@H_502_2@)@H_502_2@ *@H_502_2@(@H_502_2@(@H_502_2@*@H_502_2@(@H_502_2@@H_502_2@secondElementPtr)@H_502_2@)@H_502_2@)@H_502_2@ =@H_502_2@ "!!!"@H_502_2@ fmt.@H_502_2@(@H_502_2@@H_502_2@slice)@H_502_2@ @H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@@H_502_2@

打印出来的内容

2@H_502_2@ [@H_502_2@hello !@H_502_2@!@H_502_2@!@H_502_2@]@H_502_2@ @H_502_2@@H_502_2@@H_502_2@@H_502_2@

Map

对于 Map 类型来说,没有 reflect.ValueOf 之外的获取内容的方式。所以还是只能老老实实地用golang自带的值反射api。

猜你在找的Go相关文章