Slice vs map for set in golang
Date: 15 Aug 2015Author: Erik Dubbelboer
Ever wonder if it’s faster to use a slice or map to represent a set in go? I wrote the following program to find out:
package main
import (
"fmt"
"math/rand"
"time"
)
const maxSize = 26
const tests = 20000000
const findMult = 9999999999 // 100 = 1% hit rate, 1 = 100% hit rate.
type lst []int
func (l lst) has(xxxx int) bool {
for _, i := range l {
if i == xxxx {
return true
}
}
return false
}
type mp map[int]struct{}
func (m mp) has(xxxx int) bool {
_, ok := m[xxxx]
return ok
}
func main() {
rand.Seed(time.Now().UnixNano())
for size := 1; size < maxSize; size++ {
l := make(lst, 0, size)
m := make(mp, size)
for i := 0; i < size; i++ {
e := rand.Int()
l = append(l, e)
m[e] = struct{}{}
}
found := 0
start := time.Now()
for x := 0; x < tests; x++ {
xxxx := rand.Intn(size * findMult)
if l.has(xxxx) {
found++
}
}
sliceDuration := time.Now().Sub(start)
start = time.Now()
for x := 0; x < tests; x++ {
xxxx := rand.Intn(size * findMult)
if m.has(xxxx) {
found++
}
}
mapDuration := time.Now().Sub(start)
// Do something with found so it doesn't get optimized away.
if found > 0 {
rand.Int()
}
fmt.Printf("%d\t%v\n", size, sliceDuration-mapDuration)
}
}
And here is the output:
$ ./bench.sh 1 -261.887532ms 2 -283.816189ms 3 -180.629338ms 4 -273.558558ms 5 -170.395637ms 6 -110.11527ms 7 -238.179383ms 8 -86.595302ms 9 -386.665905ms 10 -230.164293ms 11 -240.030718ms 12 -310.295027ms 13 -183.209792ms 14 -172.458055ms 15 -210.97313ms 16 -130.370425ms 17 -134.322002ms 18 37.839305ms 19 49.001029ms 20 35.248726ms 21 158.058773ms 22 231.8019ms 23 1.846585ms 24 39.449983ms 25 33.189299ms
Conclusion
As you can see, for less than 18 elements a slice seems to be faster than a map.
Here is the resulting set that I wrote: github.com/ErikDubbelboer/set
The out of place timings you see around 7, 15 and 23 probably have to do with the number of elements go stores per bucket. But I haven’t had the time to look into this.
comments powered by Disqus