doupingyun73833 2018-11-20 07:43
浏览 167
已采纳

内存高效执行go map?

My use case is to transfer a group of members (integers) over network, so we employ delta encoding and on the receiving end we decode and put the whole list as a map, map[string]struct{} for O(1) complexity for membership check.

The problem I am facing is that the actual size of members is only 15MB for 2 Million integers, but the size of the map in heap is 100+MB. Seems like the actual map implementation of Go is not suitable for large maps. Since it is a client side SDK, I do not want to impact the usable memory much, and there can be multiple such groups that need to be kept in memory for long periods of time--around 1 week.

Is there a better alternative DS in Go for this?

type void struct{}
func ToMap(v []int64) map[string]void {
 out := map[string]void{}
 for _, i := range v {
   out[strconv.Itoa(int(i))] = void{}
 }
 return out
}
  • 写回答

1条回答 默认 最新

  • dtqu72830 2018-11-20 08:30
    关注

    This is a more memory efficient form of the map:

    type void struct{}
    
    func ToMap(v []int64) map[int64]void {
        m := make(map[int64]void, len(v))
        for _, i := range v {
            m[i] = void{}
        }
        return m
    }
    

    Go maps are optimized for integer keys. Optimize the map allocation by giving the exact map size as a hint.

    A string has an implicit pointer which would make the garbage collector (gc) follow the pointer every time it scans.


    Here is a Go benchmark for 2 million pseudorandom integers:

    package main
    
    import (
        "math/rand"
        "strconv"
        "testing"
    )
    
    type void struct{}
    
    func ToMap1(v []int64) map[string]void {
        out := map[string]void{}
        for _, i := range v {
            out[strconv.Itoa(int(i))] = void{}
        }
        return out
    }
    
    func ToMap2(v []int64) map[int64]void {
        m := make(map[int64]void, len(v))
        for _, i := range v {
            m[i] = void{}
        }
        return m
    }
    
    var benchmarkV = func() []int64 {
        v := make([]int64, 2000000)
        for i := range v {
            v[i] = rand.Int63()
        }
        return v
    }()
    
    func BenchmarkToMap1(b *testing.B) {
        b.ReportAllocs()
        b.ResetTimer()
        for N := 0; N < b.N; N++ {
            ToMap1(benchmarkV)
        }
    }
    
    func BenchmarkToMap2(b *testing.B) {
        b.ReportAllocs()
        b.ResetTimer()
        for N := 0; N < b.N; N++ {
            ToMap2(benchmarkV)
        }
    }
    

    Output:

    $ go test tomap_test.go -bench=.
    BenchmarkToMap1-4     2  973358894 ns/op    235475280 B/op    2076779 allocs/op
    BenchmarkToMap2-4    10  188489170 ns/op     44852584 B/op         23 allocs/op
    $ 
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程