加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-16 18:22:36 所属栏目:大数据 来源:网络整理
导读:golang 的反射很慢。这个和它的 api 设计有关。在 java 里面,我们一般使用反射都是这样来弄的。 Field field = clazz . getField ( "hello" ) ; field . get ( obj1 ) ; field . ( obj2 ) ; 这个取得的反射对象类型是 java.lang.reflect.Field。它是可以复
golang 的反射很慢。这个和它的 api 设计有关。在 java 里面,我们一般使用反射都是这样来弄的。
Field field = clazz.getField("hello");
field.get(obj1);
field.(obj2);

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

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

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

ValueOf(obj) fieldValue := type_. 这里取出来的 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 := uintptr(structPtr) + field.Offset

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

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

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

获取 interface{} 的指针

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

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

Slice

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

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

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

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

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

打印出来的内容

2 [hello !!!]

Map

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读