-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Closed
Milestone
Description
Line 303 in db8142f
func makemap(t *maptype, hint int, h *hmap) *hmap { |
runtime.makemap()
gives a way to reuse old hmap's buckets, but it is only used when mallocating small maps on stack at present. Why not open this shortcut to users for memory reusing? Actually I only need exporting runtime.makemap()
and runtime.clearmap()
to achieve this goal:
func resetMap(mtyp *mapType, ptr unsafe.Pointer) {
m := *(*unsafe.Pointer)(ptr)
if m == nil {
return
}
hm := (*hmap)(m)
old := hm.B
mapclear(mtyp, hm)
hm = makemap(mtyp, 0, hm)
hm.B = old
*(*unsafe.Pointer)(ptr) = m
}
It works fine and benefits much on big maps. This is the benchmark results I got on operating a 1000-keys map (one op includes make(map[int]interface{}), set 1000 keys and get 1000 keys):
func BenchmarkMap1000_ResetAndSet(b *testing.B) {
var pool = sync.Pool{
New: func() interface{} {
m := make(map[int]interface{}, 0)
return &m
},
}
for n := 0; n < b.N; n++ {
x := pool.Get()
obj, _ := x.(*map[int]interface{})
m := *obj
for i := 0; i < 1000; i++ {
m[i] = i
if ni, ok := m[i]; !ok || ni != i {
b.Fatalf("exp:%v, got:%v", i, ni)
}
}
resetMap(mtype(unpackEface(m).typ), unsafe.Pointer(obj))
pool.Put(obj)
}
}
func BenchmarkMap1000_MallocAndSet(b *testing.B) {
var obj map[int]interface{}
for n := 0; n < b.N; n++ {
obj = make(map[int]interface{})
for i := 0; i < 1000; i++ {
obj[i] = i
if ni, ok := obj[i]; !ok || ni != i {
b.Fatalf("exp:%v, got:%v", i, ni)
}
}
}
obj[1] = 1
}
//-------------RESULTS----------------
goos: darwin
goarch: amd64
pkg: code.byted.org/gopkg/memset
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkMap1000_ResetAndSet-16 23750 47376 ns/op 5957 B/op 744 allocs/op
BenchmarkMap1000_MallocAndSet-16 9390 119347 ns/op 128288 B/op 785 allocs/op