It is common to use integer types as keys in maps due low memeory allocation leading to better performance. For example int8 occupies a single byte of memory. An empty struct in golang have a minimum size of zero bytes, but they may have a size greater than zero due to padding. The size of an empty struct in Go is implementation-dependent, and it is usually 1 byte or larger to ensure that each instance of a struct has a unique memory address.
package main
import (
"fmt"
"unsafe"
)
type EmptyStruct struct{}
func main() {
size := unsafe.Sizeof(EmptyStruct{})
fmt.Println(size) // Output: 0
}
We can therfore assume in terms of performance and memory use, using empty structs as keys for context values in Go can be a more efficient choice compared to using int8 values.
We can confirm this using a benchmark test.
package main
import (
"context"
"testing"
)
func insertGetCtx(key, value interface{}) {
ctx := context.WithValue(context.Background(), key, value)
_ = ctx.Value(key)
}
func BenchmarkInsertGetCtx(b *testing.B) {
val := "some-value"
b.Run("string-key", func(b *testing.B) {
for i := 0; i < b.N; i++ {
type ctxKey string
const myKey ctxKey = "string-key"
insertGetCtx(myKey, val)
}
})
b.Run("int-key", func(b *testing.B) {
for i := 0; i < b.N; i++ {
type ctxKey int
const myKey ctxKey = 1
insertGetCtx(myKey, val)
}
})
b.Run("empty-struct-key", func(b *testing.B) {
for i := 0; i < b.N; i++ {
type ctxKey struct{}
insertGetCtx(ctxKey{}, val)
}
})
}
The results of the benchmark form 10,000,000 iterations show our earlier aassumption.
go test -bench=. -benchtime=10000000x ✔
goos: linux
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
BenchmarkInsertGetCtx/string-key-8 10000000 90.75 ns/op
BenchmarkInsertGetCtx/int-key-8 10000000 83.70 ns/op
BenchmarkInsertGetCtx/empty-struct-key-8 10000000 79.37 ns/op
PASS
ok test 2.543s
The idea was to isolate the performance impact of using different key types. I was trying to avoid compiler optimizations for previously used types. Of course for real world use this would not be the case where the key can be defined once and used multiple times.