Description
All of the benchmarks mentioned below, and a full description can be found here.
I'm experiencing some performance issues with my GopherJS PouchDB bindings, so this morning I wrote some benchmarks, and found that Promises seem to have 100~200x the overhead of callbacks:
BenchmarkDoPromise1 1000 1318000 ns/op
BenchmarkDoPromise2 2000 1253000 ns/op
BenchmarkDoPromise3 1000 2358000 ns/op
BenchmarkDoCallback1 200000 9715 ns/op
BenchmarkDoCallback2 200000 6280 ns/op
In the spirit of @r-l-x's benchmarks on PR #558, I added two more tests, to benchmark only the channel operations:
func BenchmarkRawPromise(b *testing.B) {
ch := make(chan promiseResult)
defer close(ch)
b.ResetTimer()
b.StopTimer()
for i := 0; i < b.N; i++ {
js.Global.Call("EmptyPromise").Call("then", func(r *js.Object) {
b.StartTimer()
ch <- promiseResult{result: r.String()}
})
<-ch
b.StopTimer()
}
}
func BenchmarkRawCalback(b *testing.B) {
ch := make(chan promiseResult, 1)
defer close(ch)
b.ResetTimer()
b.StopTimer()
for i := 0; i < b.N; i++ {
js.Global.Call("EmptyCallback", func(r *js.Object) {
b.StartTimer()
ch <- promiseResult{result: r.String()}
})
<-ch
b.StopTimer()
}
}
Of particular note, the code between b.StartTimer()
and b.StopTimer()
is identical in both tests:
b.StartTimer()
ch <- promiseResult{result: r.String()}
})
<-ch
b.StopTimer()
Yet the results are drastically different (by a factor of ~200x):
BenchmarkRawPromise 2000 1156000 ns/op
BenchmarkRawCalback 200000 6070 ns/op
So I then added BenchmarkChannel
, and BenchmarkChannelInGoroutine
:
func BenchmarkChannel(b *testing.B) {
ch := make(chan int, 1)
defer close(ch)
b.ResetTimer()
b.StopTimer()
for i := 0; i < b.N; i++ {
b.StartTimer()
ch <- 0
<-ch
b.StopTimer()
}
}
func BenchmarkChannelInGoroutine(b *testing.B) {
ch := make(chan int, 1)
defer close(ch)
b.ResetTimer()
b.StopTimer()
for i := 0; i < b.N; i++ {
go func() {
b.StartTimer()
ch <- 0
}()
<-ch
b.StopTimer()
}
}
With the following results:
BenchmarkChannel 500000 2968 ns/op
BenchmarkChannelInGoroutine 300000 5056 ns/op
This seems intuitive to me, and aligns with the result of BenchmarkRawCallback
. So why the drastic difference with Promises?
What am I overlooking? Is there a reason to expect this disparity?