Skip to content

Benchmarks

These numbers measure gollback alone: the functions return at once, so what’s left is the cost of starting goroutines, collecting results and cancelling. Your functions will dominate a real call; the point is that gollback adds as little as possible.

In every race, one function wins at once and the others wait to be cancelled, as the slower replicas of a real request do. With 16 callers or goroutines at once, the time is wall time per call across all of them, so it measures throughput, not the latency of one call.

Both versions ran on the same harness, with the same functions.

Time per call to Race, lower is better
Show as a table
Time per call to Race: time and allocations, v1 against v2
Scenariov1v2
1 function762.3 ns13 allocs347.5 ns5 allocs
4 functions1.95 µs22 allocs1.35 µs8 allocs
16 functions5.63 µs58 allocs3.94 µs20 allocs
4 functions, all fail2.19 µs22 allocs1.08 µs11 allocs
4 functions, 16 callers at once445.6 ns22 allocs284.4 ns8 allocs

Apple M4 Max, Go 1.27.0, median of 5 runs.

v1 started a goroutine to collect each race and sent every result through a channel; v2 starts one goroutine per function and nothing else, and keeps results in one place behind a lock. All runs its first function on your goroutine, so All of one function no longer starts a goroutine at all.

BenchmarkTimeMemoryAllocations
Race/1Race one function343.7 ns352 B5
Race/4One winner, three losers that wait to be cancelled1.37 µs448 B8
Race/16One winner, fifteen losers4.05 µs834 B20
RaceAllFailFour functions that all fail, errors joined1.10 µs600 B11
RaceParallelRace/4 from 16 goroutines at once273.1 ns448 B8
All/1One function, run on the caller's goroutine13.7 ns24 B2
All/4Four functions741.0 ns304 B6
All/16Sixteen functions2.76 µs976 B18
AllParallelAll/4 from 16 goroutines at once181.4 ns304 B6
Retry/1Succeeds on the first attempt2.5 ns0 B0
Retry/5Succeeds on the fifth attempt10.7 ns0 B0

From a clone of the repository:

Terminal window
go test -run '^$' -bench . -benchmem

To compare two versions, run each a few times and compare with benchstat:

Terminal window
go test -run '^$' -bench . -count 10 > new.txt
benchstat old.txt new.txt

The allocation counts are also enforced by tests: TestAllocations fails if a call allocates more than it should.