Created
October 15, 2025 17:35
-
-
Save ifraixedes/912c6260ac5de02c649c05140b27f9bb to your computer and use it in GitHub Desktop.
The Go test file that used to benchmark allocations of sync.Pool and I wrote a post about https://blog.fraixed.es/post/move-to-heap-golang-std-pool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This was a benchmark that I used to understand how to use sync.Pool without allocations. | |
// Pointers key as stated in the documentation, but how you use them is also important. | |
// I wrote about it in https://blog.fraixed.es/post/move-to-heap-golang-std-pool | |
// To execute the benchmarks use `go test -bench . -benchmem`. The only interesting part is the last | |
// column, the `allocs/op`; when the benchmark function shows 0 is good, otherwise is bad. | |
package tmp | |
import ( | |
"sync" | |
"testing" | |
) | |
const numElems = 10000 | |
func BenchmarkPoolPointer(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
s := pool.Get().(*[]byte) | |
if len(*s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s2 := *s | |
s2 = s2[:0] | |
pool.Put(&s2) | |
for b.Loop() { | |
s := pool.Get().(*[]byte) | |
s2 := *s | |
s2 = append(s2, 10) | |
if len(s2) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s2 = s2[:0] | |
pool.Put(&s2) | |
} | |
} | |
func BenchmarkPoolPointer2(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
s := pool.Get().(*[]byte) | |
if len(*s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s2 := *s | |
s2 = s2[:0] | |
*s = s2 | |
pool.Put(s) | |
for b.Loop() { | |
s := pool.Get().(*[]byte) | |
s2 := *s | |
s2 = append(s2, 10) | |
if len(s2) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s2 = s2[:0] | |
*s = s2 | |
pool.Put(s) | |
} | |
} | |
func BenchmarkPoolPointer3(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
s := pool.Get().(*[]byte) | |
if len(*s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
*s = (*s)[:0] | |
pool.Put(s) | |
for b.Loop() { | |
s := pool.Get().(*[]byte) | |
*s = append(*s, 10) | |
if len(*s) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
*s = (*s)[:0] | |
pool.Put(s) | |
} | |
} | |
func BenchmarkPoolValue(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
return make([]byte, 0, numElems) | |
}, | |
} | |
s := pool.Get().([]byte) | |
if len(s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = s[:0] | |
pool.Put(s) | |
for b.Loop() { | |
s := pool.Get().([]byte) | |
s = append(s, 10) | |
if len(s) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = s[:0] | |
pool.Put(s) | |
} | |
} | |
func BenchmarkPoolWrapper(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
get := func() []byte { | |
s := pool.Get().(*[]byte) | |
return *s | |
} | |
put := func(s []byte) { | |
pool.Put(&s) | |
} | |
s := get() | |
if len(s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = s[:0] | |
put(s) | |
for b.Loop() { | |
s := get() | |
s = append(s, 10) | |
if len(s) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = s[:0] | |
put(s) | |
} | |
} | |
func BenchmarkPoolWrapperPointers(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
appendByte := func(buffer *[]byte, val byte) *[]byte { | |
b := *buffer | |
b = append(b, val) | |
return &b | |
} | |
reset := func(buffer *[]byte) *[]byte { | |
b := *buffer | |
b = b[:0] | |
return &b | |
} | |
s := pool.Get().(*[]byte) | |
if len(*s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = reset(s) | |
pool.Put(s) | |
for b.Loop() { | |
s := pool.Get().(*[]byte) | |
s = appendByte(s, 10) | |
if len(*s) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = reset(s) | |
pool.Put(s) | |
} | |
} | |
func BenchmarkPoolWrapperPointers2(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
appendByte := func(buffer *[]byte, val byte) *[]byte { | |
b := *buffer | |
b = append(b, val) | |
*buffer = b | |
return buffer | |
} | |
reset := func(buffer *[]byte) *[]byte { | |
b := *buffer | |
b = b[:0] | |
*buffer = b | |
return buffer | |
} | |
s := pool.Get().(*[]byte) | |
if len(*s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = reset(s) | |
pool.Put(s) | |
for b.Loop() { | |
s := pool.Get().(*[]byte) | |
s = appendByte(s, 10) | |
if len(*s) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = reset(s) | |
pool.Put(s) | |
} | |
} | |
func BenchmarkPoolWrapperPointers3(b *testing.B) { | |
pool := sync.Pool{ | |
New: func() any { | |
s := make([]byte, 0, numElems) | |
return &s | |
}, | |
} | |
appendByte := func(buffer *[]byte, val byte) *[]byte { | |
b := append(*buffer, val) | |
*buffer = b | |
return buffer | |
} | |
reset := func(buffer *[]byte) *[]byte { | |
b := *buffer | |
b = b[:0] | |
*buffer = b | |
return buffer | |
} | |
s := pool.Get().(*[]byte) | |
if len(*s) != 0 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = reset(s) | |
pool.Put(s) | |
for b.Loop() { | |
s := pool.Get().(*[]byte) | |
s = appendByte(s, 10) | |
if len(*s) != 1 { | |
b.Error("returned slice doesn't have the expected number of elements") | |
} | |
s = reset(s) | |
pool.Put(s) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment