2017-10-19 4 views
3

인터페이스 {}이 주어진 함수를 구현하는지 여부를 효율적으로 테스트하려고합니다. 내 솔루션은이 함수만으로 인터페이스를 생성 한 다음 인터페이스 {}가이 단일 함수 인터페이스를 구현하는지 확인합니다. 여기서 두 가지 옵션은 반사 또는 형식 어설 션을 사용하는 것 같습니다. 두 가지 모두 동일한 동작을 보이지만 큰 속도 차이가 있습니다.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 

답변

7

유형의 주장은 runtime.assertE2I2라는 함수에 의존한다. 코드를 살펴보면, getitab에 의존하며, 같은 파일에있는 additab에 의존한다는 것을 알 수 있습니다. 이제

, 지정된 타입이 additab의 내부 인터페이스를 구현하는 경우 검사의 실제 논리는 정확히 Implementsreflect에서와 동일합니다 - 심지어이 댓글에서 지적 된 선형 검색 :

// 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). 

그러나 차이점은 additab이 실제로 캐싱을 사용한다는 것입니다. 형식 어설 션 결과가 해시 맵에 저장되므로 동일한 유형의 후속 형식 어설 션이 일정 시간에 실행되므로 성능에 큰 차이가 있음을 알 수 있습니다 .

+0

Implements()가 캐싱을하지 않는 이유가 있습니까? 이것은 인터페이스를 구현하는 것이 변경 될 수 있는지 여부를 예상하고 있습니다 (그러나 이것이 사실이라면 확실하게 형식 어설 션 캐싱이 올바르지 않습니까?) – bradleyjkemp

+0

반사가 느리기 때문에 어쨌든. – Volker

+1

@bradleyjkemp, "Computing the Itable"섹션을 참조하는 것이 좋습니다 (https://research.swtch.com/interfaces). 귀하의 의견을 귀하의 의견을 대답 : 비록 타입을 주장/스위치 및 인터페이스 유형의 변수에 콘크리트 유형의 값을 할당 런타임에 해당 유형에 대한 새로운 itable 컴퓨팅이 필요할 수 있습니다, 컴파일러는 거기에만 유한 수 있다고 추정 분명한 프로그램에서 그러한 계산의 수는 간단합니다. 왜냐하면 Go 프로그램이 런타임시 자체를 변경할 수 없기 때문입니다 ... – kostix

관련 문제