HaxMap
一个极快的并发哈希图
这项工作源于Cornelk-hashmap,并对性能和API进行了进一步的改进。
安装
你需要Golang1.19.x或以上版本。
$ go get github.com/alphadose/haxmap
使用方法
支持的地图键类型 ->int,uint,uintptr 。string
package main
import (
"fmt"
"github.com/alphadose/haxmap"
)
func main() {
// initialize map with key type `int` and value type `string`
mep := haxmap.New[int, string]()
// set a value (overwrites existing value if present)
mep.Set(1, "one")
// get the value and print it
val, ok := mep.Get(1)
if ok {
println(val)
}
mep.Set(2, "two")
mep.Set(3, "three")
// ForEach loop to iterate over all key-value pairs and execute the given lambda
mep.ForEach(func(key int, value string) {
fmt.Printf("Key -> %d | Value -> %s\n", key, value)
})
// delete values
mep.Del(1)
mep.Del(2)
mep.Del(3)
mep.Del(0) // delete is safe even if a key doesn't exists
if mep.Len() == 0 {
println("cleanup complete")
}
}
基准测试
基准测试是针对golang sync.Map和cornelk-hashmap进行的。
所有的结果都是从30次运行的benchstat中计算出来的(代码可在此获得)。
- 仅限并发读取
name time/op
HaxMapReadsOnly-8 11.1µs ±12%
GoSyncMapReadsOnly-8 22.0µs ±13%
CornelkMapReadsOnly-8 16.7µs ± 6%
name alloc/op
HaxMapReadsOnly-8 0.00B
GoSyncMapReadsOnly-8 0.00B
CornelkMapReadsOnly-8 7.43B ± 8%
name allocs/op
HaxMapReadsOnly-8 0.00
GoSyncMapReadsOnly-8 0.00
CornelkMapReadsOnly-8 0.00
- 并发读与写
name time/op
HaxMapReadsWithWrites-8 13.1µs ±11%
GoSyncMapReadsWithWrites-8 25.0µs ±12%
CornelkMapReadsWithWrites-8 20.0µs ± 6%
name alloc/op
HaxMapReadsWithWrites-8 6.71kB ± 9%
GoSyncMapReadsWithWrites-8 6.32kB ± 6%
CornelkMapReadsWithWrites-8 10.0kB ± 9%
name allocs/op
HaxMapReadsWithWrites-8 239 ± 9%
GoSyncMapReadsWithWrites-8 585 ± 6%
CornelkMapReadsWithWrites-8 407 ± 9%
从以上结果可以看出,haxmap 是目前最快的golang并发哈希图,它具有最少的allocs/op ,并且动态内存占用率低。
提示
- HaxMap默认使用xxHash算法,但你可以覆盖它,并插入你自己的自定义哈希函数。下面是一个同样的例子:
package main
import (
"github.com/alphadose/haxmap"
)
// your custom hash function
// the hash function signature must adhere to `func(keyType) uintptr`
// where keyType ∈ {int, uint, uintptr, string}
func customStringHasher(s string) uintptr {
return uintptr(len(s))
}
func main() {
// initialize a string-string map with your custom hash function
// this overrides the default xxHash algorithm
m := &haxmap.HashMap[string, string]{Hasher: customStringHasher}
m.Set("one", "1")
val, ok := m.Get("one")
if ok {
println(val)
}
}
- 你可以预先分配地图的大小,这在某些情况下会提高性能:
package main
import (
"github.com/alphadose/haxmap"
)
func main() {
const initialSize = 1 << 10
// pre-allocating the size of the map will prevent all grow operations
// until that limit is hit thereby improving performance
m := haxmap.New[int, string](initialSize)
m.Set(1, "1")
val, ok := m.Get(1)
if ok {
println(val)
}
}