HaxMap
A lightning fast concurrent hashmap
The hashing algorithm used was xxHash and the hashmap's buckets were implemented using Harris lock-free list
Installation
You need Golang 1.18.x or above
$ go get github.com/alphadose/haxmap
Usage
package main
import (
"fmt"
"github.com/alphadose/haxmap"
)
func main() {
mep := haxmap.New[int, string]()
mep.Set(1, "one")
val, ok := mep.Get(1)
if ok {
println(val)
}
mep.Set(2, "two")
mep.Set(3, "three")
mep.Set(4, "four")
mep.ForEach(func(key int, value string) bool {
fmt.Printf("Key -> %d | Value -> %s\n", key, value)
return true
})
mep.Del(1)
mep.Del(0)
mep.Del(2, 3, 4)
if mep.Len() == 0 {
println("cleanup complete")
}
}
Benchmarks
Benchmarks were performed against golang sync.Map and the latest cornelk-hashmap
All results were computed from benchstat of 20 runs (code available here)
- Concurrent Reads Only
name time/op
HaxMapReadsOnly-8 6.94µs ± 4%
GoSyncMapReadsOnly-8 21.5µs ± 3%
CornelkMapReadsOnly-8 8.39µs ± 8%
- Concurrent Reads with Writes
name time/op
HaxMapReadsWithWrites-8 8.23µs ± 3%
GoSyncMapReadsWithWrites-8 25.0µs ± 2%
CornelkMapReadsWithWrites-8 8.83µs ±20%
name alloc/op
HaxMapReadsWithWrites-8 1.25kB ± 5%
GoSyncMapReadsWithWrites-8 6.20kB ± 7%
CornelkMapReadsWithWrites-8 1.53kB ± 9%
name allocs/op
HaxMapReadsWithWrites-8 156 ± 5%
GoSyncMapReadsWithWrites-8 574 ± 7%
CornelkMapReadsWithWrites-8 191 ± 9%
From the above results it is evident that haxmap
takes the least time, memory and allocations in all cases making it the best golang concurrent hashmap in this period of time
Tips
- HaxMap by default uses xxHash algorithm, but you can override this and plug-in your own custom hash function. Beneath lies an example for the same.
package main
import (
"github.com/alphadose/haxmap"
)
func customStringHasher(s string) uintptr {
return uintptr(len(s))
}
func main() {
m := haxmap.New[string, string]()
m.SetHasher(customStringHasher)
m.Set("one", "1")
val, ok := m.Get("one")
if ok {
println(val)
}
}
- You can pre-allocate the size of the map which will improve performance in some cases.
package main
import (
"github.com/alphadose/haxmap"
)
func main() {
const initialSize = 1 << 10
m := haxmap.New[int, string](initialSize)
m.Set(1, "1")
val, ok := m.Get(1)
if ok {
println(val)
}
}