Benchmarks
These numbers measure the pool alone: a job is an int and the workers do nothing with it, so what’s left is
the cost of queueing a job and handing it to a worker. Your jobs will dominate a real run; the point is that
the pool adds as little as possible.
Delegate alone runs into a queue with room for every job. A job through workers runs through a queue of 1024:
when the workers fall behind, Delegate waits, so the time per job is the pace of the whole pool. With 16
callers at once, the time is wall time per call across all of them, so it measures throughput.
v3 against v2
Section titled “v3 against v2”Both versions ran on the same harness, with the same jobs.
Show as a table
| Scenario | v2 | v3 |
|---|---|---|
| 1 worker | 215.9 ns2 allocs | 38.8 ns0 allocs |
| 16 workers | 412.1 ns2 allocs | 110.1 ns0 allocs |
| 1 worker, 16 callers at once | 372.3 ns2 allocs | 86.9 ns0 allocs |
| 16 workers, 16 callers at once | 258.3 ns2 allocs | 55.4 ns0 allocs |
Apple M4 Max, Go 1.27.0, median of 5 runs.
Show as a table
| Scenario | v2 | v3 |
|---|---|---|
| queue has room | 32.6 ns2 allocs | 11.4 ns0 allocs |
| queue has room, 16 callers at once | 86.0 ns2 allocs | 35.4 ns0 allocs |
Apple M4 Max, Go 1.27.0, median of 5 runs.
v2 built a slice of reflect.Values for every job, boxing each argument, and called the worker with
reflect.Value.Call. v3 sends the job on a typed channel and calls the worker’s func directly.
With jobs that do nothing, one caller can’t keep 16 workers busy: they wait and wake for every job, which costs more than the job itself. With real work, the workers stay busy and take jobs straight from the queue.
v3’s own suite
Section titled “v3’s own suite”| Benchmark | Time | Memory | Allocations |
|---|---|---|---|
DelegateInto a queue with room, no worker | 11.0 ns | 0 B | 0 |
Job/workers=1One caller, one worker, a queue of 1024 | 38.0 ns | 0 B | 0 |
Job/workers=16One caller, sixteen workers | 104.1 ns | 0 B | 0 |
JobParallelSixteen callers, sixteen workers | 46.2 ns | 0 B | 0 |
Run them yourself
Section titled “Run them yourself”From a clone of the repository:
go test -run '^$' -bench . -benchmemTo compare two versions, run each a few times and compare with benchstat:
go test -run '^$' -bench . -count 10 > new.txtbenchstat old.txt new.txtThe allocation counts are also enforced by tests: TestAllocations fails if a call allocates more than it should.