dstt1818 2017-10-19 19:29
浏览 72
已采纳

为什么反射Type.Implements()比类型断言这么慢?

I'm trying to efficiently test whether an interface{} implements a given function and my solution is to create an interface with just this function and then check whether the interface{} implements this single function interface. The two options here seem to be either using reflection or a type assertion. Both seem to have identical behaviour however there is a large speed difference.

Looking at the code for Value.Implements() it does a linear scan over the functions defined on the value and compares them against the interface. The type assertion however just seems to do a constant time comparison (independent of the number of functions in the interface).

Is there a reason why Implements() doesn't just do a type assertion?

Benchmark:

package benchmarks

import (
    "reflect"
    "testing"
)

type ITest interface {
    Foo()
}

type Base struct{}

func (Base) A() {}
func (Base) B() {}
func (Base) C() {}
func (Base) D() {}
func (Base) E() {}
func (Base) F() {}
func (Base) G() {}
func (Base) H() {}
func (Base) I() {}
func (Base) J() {}

var Interface = reflect.TypeOf((*ITest)(nil)).Elem()

func BenchmarkReflection(b *testing.B) {
    var iface interface{}
    iface = Base{}
    for i := 0; i < b.N; i++ {
        if reflect.TypeOf(iface).Implements(Interface) {
            b.FailNow()
        }
    }
}

func BenchmarkAssertion(b *testing.B) {
    var iface interface{}
    iface = Base{}
    for i := 0; i < b.N; i++ {
        if _, ok := iface.(ITest); ok {
            b.FailNow()
        }
    }
}

Results:

go test -run=XXX -bench=. so_test.go
goos: linux
goarch: amd64
BenchmarkReflection-8           10000000                  208 ns/op
BenchmarkAssertion-8            200000000                9.24 ns/op
PASS
ok      command-line-arguments  5.115s
  • 写回答

1条回答 默认 最新

  • duan0531 2017-10-20 00:24
    关注

    Type assertion in Go relies on a function called runtime.assertE2I2. If you look into the code, you'll notice it relies on getitab which in turn relies on additab (in the same file).

    Now, the actual logic of checking if the given type implements an interface inside of additab is exactly the same as Implements in reflect - a linear search, which is even pointed out in this comment:

    // both inter and typ have method sorted by name,
    // and interface names are unique,
    // so can iterate over both in lock step;
    // the loop is O(ni+nt) not O(ni*nt).
    

    However, the difference is that additab actually utilises caching - the result of the type assertion is stored in a hash map, so subsequent type assertions for the same type will run in constant time, which is why you're seeing a huge difference in performance.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?