Skip to content

Instantly share code, notes, and snippets.

@SchumacherFM
Last active May 18, 2022 08:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save SchumacherFM/876741809c1b99d4d81b to your computer and use it in GitHub Desktop.
Save SchumacherFM/876741809c1b99d4d81b to your computer and use it in GitHub Desktop.
GoLang Benchmark: Map, StringSlice, Array, StructSlice
package main
// run with: $ go test --bench=. -test.benchmem .
// @see https://twitter.com/karlseguin/status/524452778093977600
import (
"math/rand"
"strconv"
"testing"
)
const (
SIZE = 10
LOOKUPS = 200
)
// Excluded means that the setup of the lookup variable is created once outside the bench loop
// Included means that the setup of the lookup variable is created new each loop
func BenchmarkStringMapExcluded(b *testing.B) {
lookup := make(map[string]string, SIZE)
for i := 0; i < SIZE; i += 1 {
k := strconv.Itoa(i) // FYI: converts int to string
lookup[k] = "value"
}
rand.Seed(int64(b.N))
b.ResetTimer()
for n := 0; n < b.N; n++ {
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
if _, ok := lookup[needle]; ok {
}
}
}
}
func BenchmarkStringMapIncluded(b *testing.B) {
rand.Seed(int64(b.N))
b.ResetTimer()
for n := 0; n < b.N; n++ {
lookup := make(map[string]string, SIZE)
for i := 0; i < SIZE; i += 1 {
k := strconv.Itoa(i) // FYI: converts int to string
lookup[k] = "value"
}
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
if _, ok := lookup[needle]; ok {
}
}
}
}
func BenchmarkStringSliceExcluded(b *testing.B) {
lookup := make([]string, SIZE*2)
for i := 0; i < SIZE; i += 2 {
lookup[i] = strconv.Itoa(i / 2)
lookup[i+1] = "value"
}
rand.Seed(int64(b.N))
b.ResetTimer()
for n := 0; n < b.N; n++ {
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
for j := 0; j < SIZE; j += 2 {
if lookup[j] == needle {
}
}
}
}
}
func BenchmarkStringSliceIncluded(b *testing.B) {
rand.Seed(int64(b.N))
b.ResetTimer()
for n := 0; n < b.N; n++ {
lookup := make([]string, SIZE*2)
for i := 0; i < SIZE; i += 2 {
lookup[i] = strconv.Itoa(i / 2)
lookup[i+1] = "value"
}
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
for j := 0; j < SIZE; j += 2 {
if lookup[j] == needle {
}
}
}
}
}
func BenchmarkStringArraysExcluded(b *testing.B) {
lookup := [SIZE * 2]string{}
for i := 0; i < SIZE; i += 2 {
lookup[i] = strconv.Itoa(i / 2)
lookup[i+1] = "value"
}
rand.Seed(int64(b.N))
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
for j := 0; j < SIZE; j += 2 {
if lookup[j] == needle {
}
}
}
}
}
func BenchmarkStringArraysIncluded(b *testing.B) {
rand.Seed(int64(b.N))
b.ResetTimer()
for i := 0; i < b.N; i++ {
lookup := [SIZE * 2]string{}
for i := 0; i < SIZE; i += 2 {
lookup[i] = strconv.Itoa(i / 2)
lookup[i+1] = "value"
}
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
for j := 0; j < SIZE; j += 2 {
if lookup[j] == needle {
}
}
}
}
}
func BenchmarkStructSliceExcluded(b *testing.B) {
lookup := make([]struct{ key, value string }, SIZE)
for i := 0; i < SIZE; i++ {
lookup[i].key = strconv.Itoa(i)
lookup[i].value = "value"
}
rand.Seed(int64(b.N))
b.ResetTimer()
for n := 0; n < b.N; n++ {
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
for j := 0; j < SIZE; j++ {
if lookup[j].key == needle {
}
}
}
}
}
func BenchmarkStructSliceIncluded(b *testing.B) {
rand.Seed(int64(b.N))
b.ResetTimer()
for n := 0; n < b.N; n++ {
lookup := make([]struct{ key, value string }, SIZE)
for i := 0; i < SIZE; i++ {
lookup[i].key = strconv.Itoa(i)
lookup[i].value = "value"
}
for i := 0; i < LOOKUPS; i++ {
needle := strconv.Itoa(rand.Intn(SIZE))
for j := 0; j < SIZE; j++ {
if lookup[j].key == needle {
}
}
}
}
}
@SchumacherFM
Copy link
Author

MacBook Air Mid 2012; 1.8 GHz Intel Core i5

$ go test --bench=. -v .
PASS
BenchmarkStringMap   1000000          1852 ns/op
BenchmarkStringSlice       10000        173926 ns/op
BenchmarkStringArrays      10000        179837 ns/op
BenchmarkStructSlice        5000        413109 ns/op
ok                                               7.571s

@SchumacherFM
Copy link
Author

$ go test --bench=. -test.benchmem .
PASS
BenchmarkStringMapExcluded    100000         28148 ns/op         200 B/op         12 allocs/op
BenchmarkStringMapIncluded    100000         29652 ns/op         846 B/op         15 allocs/op
BenchmarkStringSliceExcluded      100000         28277 ns/op         200 B/op         12 allocs/op
BenchmarkStringSliceIncluded      100000         28587 ns/op         205 B/op         12 allocs/op
BenchmarkStringArraysExcluded     100000         28299 ns/op         200 B/op         12 allocs/op
BenchmarkStringArraysIncluded     100000         28262 ns/op         205 B/op         12 allocs/op
BenchmarkStructSliceExcluded       50000         39858 ns/op         200 B/op         12 allocs/op
BenchmarkStructSliceIncluded       50000         40250 ns/op         210 B/op         13 allocs/op
ok      github.com/SchumacherFM/gotest  23.697s

@shuLhan
Copy link

shuLhan commented Aug 16, 2018

@SchumacherFM which Go version did you use?

@apieceofredcloth
Copy link

For slice, why not break when match?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment