Last active
November 4, 2021 18:09
-
-
Save ncdc/65ca2bfdcd7ba56dc144f50937831a43 to your computer and use it in GitHub Desktop.
Go map benchmarks - string vs struct keys
This file contains 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
package mapbenchmark | |
import ( | |
"math/rand" | |
"strconv" | |
"testing" | |
) | |
type structKey struct { | |
one string | |
two string | |
} | |
const numKeys = 1000000 | |
func BenchmarkStringKeyGet(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
if _, ok := m[k[i]]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkStringKeyGetInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
if _, ok := m[k[i]]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkStringKeyRange(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
} | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
for kk, vv := range m { | |
_ = kk | |
_ = vv | |
} | |
} | |
} | |
func BenchmarkStringKeyRangeInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
} | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
for kk, vv := range m { | |
_ = kk | |
_ = vv | |
} | |
} | |
} | |
func BenchmarkStringKeyPut(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(k) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
m[k[i]] = "value" | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkStringKeyPutInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(k) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
m[k[i]] = "value" | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func newStructKey(i int) structKey { | |
return structKey{ | |
one: strconv.Itoa(i), | |
two: strconv.Itoa(i + 1), | |
} | |
} | |
func BenchmarkStructKeyGet(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[structKey]string) | |
k := make([]structKey, 0) | |
for i := 0; i < numKeys; i++ { | |
key := newStructKey(i) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
if _, ok := m[k[i]]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkStructKeyGetIntefface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]structKey, 0) | |
for i := 0; i < numKeys; i++ { | |
key := newStructKey(i) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
if _, ok := m[k[i]]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkStructKeyRange(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[structKey]string) | |
for i := 0; i < numKeys; i++ { | |
key := newStructKey(i) | |
m[key] = "value" + strconv.Itoa(i) | |
} | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
for kk, vv := range m { | |
_ = kk | |
_ = vv | |
} | |
} | |
} | |
func BenchmarkStructKeyRangeInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
for i := 0; i < numKeys; i++ { | |
key := newStructKey(i) | |
m[key] = "value" + strconv.Itoa(i) | |
} | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
for kk, vv := range m { | |
_ = kk | |
_ = vv | |
} | |
} | |
} | |
func BenchmarkStructKeyPut(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[structKey]string) | |
k := make([]structKey, 0) | |
for i := 0; i < numKeys; i++ { | |
k = append(k, newStructKey(i)) | |
} | |
i := 0 | |
l := len(k) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
m[k[i]] = "value" | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkStructKeyPutInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]structKey, 0) | |
for i := 0; i < numKeys; i++ { | |
k = append(k, newStructKey(i)) | |
} | |
i := 0 | |
l := len(k) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
m[k[i]] = "value" | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} |
This file contains 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
goos: darwin | |
goarch: amd64 | |
pkg: map-key-benchmarks | |
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz | |
BenchmarkStringKeyGet-12 10713081 112.0 ns/op 0 B/op 0 allocs/op | |
BenchmarkStringKeyGetInterface-12 6465774 186.3 ns/op 0 B/op 0 allocs/op | |
BenchmarkStringKeyRange-12 145 8210280 ns/op 0 B/op 0 allocs/op | |
BenchmarkStringKeyRangeInterface-12 147 8085765 ns/op 0 B/op 0 allocs/op | |
BenchmarkStringKeyPut-12 9652598 124.0 ns/op 8 B/op 0 allocs/op | |
BenchmarkStringKeyPutInterface-12 3594646 314.0 ns/op 38 B/op 1 allocs/op | |
BenchmarkStructKeyGet-12 9254334 132.2 ns/op 0 B/op 0 allocs/op | |
BenchmarkStructKeyGetIntefface-12 7211918 164.3 ns/op 0 B/op 0 allocs/op | |
BenchmarkStructKeyRange-12 69 17300422 ns/op 0 B/op 0 allocs/op | |
BenchmarkStructKeyRangeInterface-12 69 15344843 ns/op 0 B/op 0 allocs/op | |
BenchmarkStructKeyPut-12 4984252 227.1 ns/op 47 B/op 0 allocs/op | |
BenchmarkStructKeyPutInterface-12 2829900 359.4 ns/op 89 B/op 1 allocs/op |
This file contains 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
package stringkey | |
import ( | |
"math/rand" | |
"strconv" | |
"strings" | |
"testing" | |
) | |
const numKeys = 1000000 | |
func BenchmarkKeyGet(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.Logf("l=%d", l) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
if _, ok := m[k[i]]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkKeyGetInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.Logf("l=%d", l) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
if _, ok := m[k[i]]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkKeyRange(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
} | |
b.Logf("l=%d", len(m)) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
for kk, vv := range m { | |
_ = kk | |
_ = vv | |
} | |
} | |
} | |
func BenchmarkKeyRangeInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
} | |
b.Logf("l=%d", len(m)) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
for kk, vv := range m { | |
_ = kk | |
_ = vv | |
} | |
} | |
} | |
func BenchmarkKeyPut(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(k) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
m[k[i]] = "value" | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkKeyPutInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(k) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
m[k[i]] = "value" | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func splitKey(key string) (string, string) { | |
parts := strings.Split(key, "/") | |
switch len(parts) { | |
case 1: | |
return "", parts[0] | |
case 2: | |
return parts[0], parts[1] | |
} | |
panic("invalid key") | |
} | |
func joinKey(namespace, name string) string { | |
if namespace != "" { | |
return namespace + "/" + name | |
} | |
return name | |
} | |
func BenchmarkControllerAccess(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[string]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) + "/" + strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.Logf("l=%d", l) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
key := k[i] | |
namespace, name := splitKey(key) | |
joined := joinKey(namespace, name) | |
if _, ok := m[joined]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} | |
func BenchmarkControllerAccessInterface(b *testing.B) { | |
b.ReportAllocs() | |
m := make(map[interface{}]string) | |
k := make([]string, 0) | |
for i := 0; i < numKeys; i++ { | |
key := strconv.Itoa(rand.Intn(numKeys)) + "/" + strconv.Itoa(rand.Intn(numKeys)) | |
m[key] = "value" + strconv.Itoa(i) | |
k = append(k, key) | |
} | |
i := 0 | |
l := len(m) | |
b.Logf("l=%d", l) | |
b.ResetTimer() | |
for n := 0; n < b.N; n++ { | |
key := k[i] | |
namespace, name := splitKey(key) | |
joined := joinKey(namespace, name) | |
if _, ok := m[joined]; !ok { | |
b.FailNow() | |
} | |
i++ | |
if i >= l { | |
i = 0 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment