인터페이스 {}이 주어진 함수를 구현하는지 여부를 효율적으로 테스트하려고합니다. 내 솔루션은이 함수만으로 인터페이스를 생성 한 다음 인터페이스 {}가이 단일 함수 인터페이스를 구현하는지 확인합니다. 여기서 두 가지 옵션은 반사 또는 형식 어설 션을 사용하는 것 같습니다. 두 가지 모두 동일한 동작을 보이지만 큰 속도 차이가 있습니다.Type.Implements()가 형식 어설 션보다 훨씬 느린 이유는 무엇입니까?
Value.Implements() 코드를 보면 값에 정의 된 함수를 선형 스캔하고 인터페이스와 비교합니다. 그러나 형식 어설 션은 일정한 시간 비교 (인터페이스의 함수 개수와 관계 없음)를 수행하는 것처럼 보입니다.
Implements()가 형식 어설 션을 수행하지 않는 이유가 있습니까?
벤치 마크 :
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()
}
}
}
결과 : 이동에
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
Implements()가 캐싱을하지 않는 이유가 있습니까? 이것은 인터페이스를 구현하는 것이 변경 될 수 있는지 여부를 예상하고 있습니다 (그러나 이것이 사실이라면 확실하게 형식 어설 션 캐싱이 올바르지 않습니까?) – bradleyjkemp
반사가 느리기 때문에 어쨌든. – Volker
@bradleyjkemp, "Computing the Itable"섹션을 참조하는 것이 좋습니다 (https://research.swtch.com/interfaces). 귀하의 의견을 귀하의 의견을 대답 : 비록 타입을 주장/스위치 및 인터페이스 유형의 변수에 콘크리트 유형의 값을 할당 런타임에 해당 유형에 대한 새로운 itable 컴퓨팅이 필요할 수 있습니다, 컴파일러는 거기에만 유한 수 있다고 추정 분명한 프로그램에서 그러한 계산의 수는 간단합니다. 왜냐하면 Go 프로그램이 런타임시 자체를 변경할 수 없기 때문입니다 ... – kostix