首页 > 解决方案 > 使用反射访问结构字段(作为字符串变量)与直接访问它的性能

问题描述

有人可以解释使用反射包访问结构字段时的性能差异,如下所示:

v := reflect.ValueOf(TargetStruct)
f := reflect.Indirect(v).FieldByName("Field")

VS使用正常方式:

f := TargetStruct.Field

我之所以问,是因为我无法找到有关实际性能的资源。我的意思是,如果直接访问(示例 2)是 O(1),那么间接访问(示例 1)的速度是多少?还有另一个因素需要考虑,期望代码不那么干净并且编译器缺少一些信息,比如字段的类型等?

标签: go

解决方案


反射慢得多,即使两个操作都是 O(1),因为大 O 表示法故意不捕获常数,并且反射有一个很大的常数(它c大约是 100,或 2 个十进制数量级,这里)。

我会稍微(但只是稍微)对Volker 的评论说反射O(1),因为这个特定的反射必须在运行时查找名称,这可能涉及也可能不涉及使用 Go map1本身未指定:请参阅golang中map的Big O表现如何? 此外,正如该问题的已接受答案中所述,无论如何,对于字符串,哈希查找并不是完全 O(1)。但同样,这一切都被反射的常数因素所淹没。

形式的操作:

f := TargetStruct.Field

通常会编译成一条机器指令,根据缓存命中情况,它可以在从一个时钟周期的一小部分到几个周期或更多周期的任何地方运行。一种形式:

v := reflect.ValueOf(TargetStruct)
f := reflect.Indirect(v).FieldByName("Field")

变成调用运行时:

  • 分配一个新的反射对象来存储v
  • 检查v(在Indirect(),看是否Elem()有必要),然后结果Indirect()是 astruct并且有一个字段,其名称是给定的,并获得该字段

并且此时您仍然只有一个reflect.Value对象 in f,因此如果您想要整数,您仍然必须找到实际值:

fv := int(Field.Int())

例如。这可能是从几十条指令到几百条指令的任何地方。这就是我c ≈ 100猜到的地方。


1当前的实现有一个带有字符串相等性测试的线性扫描。我们必须至少测试每个字符串一次,对于长度匹配的字符串,我们还必须对单个字符串字节进行额外的测试,至少直到它们不匹配为止。


推荐阅读