跳到主要内容

避坑-2-反射

二 反射的使用

反射的函数调用,也是使用反射中容易忽视的性能点,下面展示对普通函数的调用过程。

func foo(v int){
fmt.Println("函数被执行:", v)
}

// 普通调用
func BenchmarkNativeCall(b *testing.B) {
for i := 0; i < b.N; i++ {
foo(0)
}
}

// 反射调用
func BenchmarkReflectCall(b *testing.B) {
v := reflect.ValueOf(foo)
b.StartTimer()
b.ResetTimer()
b.StartTimer()
for i:= 0; i < b.N; i++ {
v.Call([]reflect.Value{reflect.ValueOf(2)})
}
}

基准测试结果:

go test -v -bench=.

使用 reflect.Value0f() 构造反射值对象,因为反射函数调用的参数必须全是反射值对象,所以再使用 []reflect.Value 构造多个参数列表传给反射值对象的 Call() 方法进行调用。反射函数调用的参数构造过程非常复杂,构建很多对象会造成很大的内存回收负担。Call()方法内部就更为复杂,需要将参数列表的每个值reflect.Value类型转换为内存。调用完毕后 ,还要将函数返回值重新转换为reflect.Value 类型返回。因此,反射调用函数的性能堪忧。