Skip to content

Instantly share code, notes, and snippets.

@mariomac
Created February 25, 2022 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mariomac/aa29de236211a8e5afedfb34c20c76ce to your computer and use it in GitHub Desktop.
Save mariomac/aa29de236211a8e5afedfb34c20c76ce to your computer and use it in GitHub Desktop.
Go reflection API performance
All the three benchmarks do the same operation:
go test -bench=. ./examples/... -test.run=^$ -benchmem -cpu 2,4,6
? github.com/mariomac/go-pipes/examples/basic [no test files]
goos: darwin
goarch: amd64
pkg: github.com/mariomac/go-pipes/examples/tests
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkNative-2 3277838 362.9 ns/op 0 B/op 0 allocs/op
BenchmarkNative-4 3263050 364.7 ns/op 0 B/op 0 allocs/op
BenchmarkNative-6 3328184 364.1 ns/op 0 B/op 0 allocs/op
BenchmarkGenerified-2 1202913 985.0 ns/op 103 B/op 6 allocs/op
BenchmarkGenerified-4 1000000 1001 ns/op 103 B/op 6 allocs/op
BenchmarkGenerified-6 1225830 1028 ns/op 104 B/op 6 allocs/op
BenchmarkGenerifiedMakeFunc-2 1546054 774.1 ns/op 64 B/op 4 allocs/op
BenchmarkGenerifiedMakeFunc-4 1470452 824.3 ns/op 64 B/op 4 allocs/op
BenchmarkGenerifiedMakeFunc-6 1438862 833.4 ns/op 64 B/op 4 allocs/op
package tests
import (
"reflect"
"testing"
)
func doubler(i int) int {
return i * 2
}
func generify(function interface{}) (in, out reflect.Value) {
fn := reflect.ValueOf(function)
inT := reflect.ChanOf(reflect.BothDir, fn.Type().In(0))
in = reflect.MakeChan(inT, 20)
outT := reflect.ChanOf(reflect.BothDir, fn.Type().Out(0))
out = reflect.MakeChan(outT, 20)
go func() {
for v, ok := in.Recv(); ok; v, ok = in.Recv() {
ret := fn.Call([]reflect.Value{v})
out.Send(ret[0])
}
}()
return in, out
}
func doubleChReflect(fn reflect.Value) func(chans []reflect.Value) []reflect.Value {
return func(chans []reflect.Value) []reflect.Value {
in, out := chans[0], chans[1]
for v, ok := in.Recv(); ok; v, ok = in.Recv() {
ret := fn.Call([]reflect.Value{v})
out.Send(ret[0])
}
return nil
}
}
func doublerCh(in <-chan int, out chan<- int) {
for i := range in {
out <- doubler(i)
}
}
func BenchmarkNative(b *testing.B) {
in, out := make(chan int, 20), make(chan int, 20)
go doublerCh(in, out)
for n := 0; n < b.N; n++ {
in <- n
<-out
}
}
func BenchmarkGenerified(b *testing.B) {
in, out := generify(doubler)
for n := 0; n < b.N; n++ {
in.Send(reflect.ValueOf(n))
v, _ := out.Recv()
_ = v.Interface()
}
}
func BenchmarkGenerifiedMakeFunc(b *testing.B) {
in, out := make(chan int, 20), make(chan int, 20)
var doublerLoop func(in <-chan int, out chan<- int)
fn := reflect.ValueOf(&doublerLoop).Elem()
actualFun := reflect.MakeFunc(fn.Type(), doubleChReflect(reflect.ValueOf(doubler)))
fn.Set(actualFun)
go doublerLoop(in, out)
for n := 0; n < b.N; n++ {
in <- n
<-out
}
}
//
//func main() {
// in, out := generify(doubler)
// in.Send(reflect.ValueOf(1))
// in.Send(reflect.ValueOf(2))
// in.Send(reflect.ValueOf(3))
//
// v, _ := out.Recv()
// fmt.Println(v.Interface())
// v, _ = out.Recv()
// fmt.Println(v.Interface())
// v, _ = out.Recv()
// fmt.Println(v.Interface())
//
// in, out = generify(stringer)
// in.Send(reflect.ValueOf(1))
// in.Send(reflect.ValueOf(2))
// in.Send(reflect.ValueOf(3))
//
// v, _ = out.Recv()
// fmt.Println(v.Interface())
// v, _ = out.Recv()
// fmt.Println(v.Interface())
// v, _ = out.Recv()
// fmt.Println(v.Interface())
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment