go - 如何分配内存以映射指向golang中的 slice

标签 go optimization memory-management

有没有办法分配映射的内存,最多有 Nmax 个键,指向最大长度 Nmax 的 slice ?

我目前只是通过 make(map[int][]int,Nmax) 指定键的最大数量,但我不确定如何告诉 Go 每个 slice 将是最大长度 Nmax 因为我不知道 key 是先验的。

我基本上有一堆人口为整数的网站。我使用 map 来跟踪有多少站点具有给定的人口 N。我的程序中的瓶颈似乎是 runtime.memmove,我猜这是由于不断调整 map 指向的 slice 的大小。

最佳答案

鉴于您对问题的描述确实相当模糊,我将首先说明我将如何“管理” map 。为简单起见,我将把所有逻辑包装在接收器函数中,因此将映射包装在自定义类型中:

type dataMap struct {
    data map[int][]int
    nmax int
}

func New(Nmax int) *dataMap {
    return &dataMap{
        data: make(map[int][]int, Nmax),
        nmax: Nmax,
    }
}

// Get - return slice for given key
func (d dataMap) Get(k int) []int {
    s, ok := d.data[k]
    if !ok {
        return nil // optionally return error
    }
    return s
}

// Set - set/append values to a given key - this is not safe for concurrent use
// if that's needed, add a RWMutex to the type
func (d *dataMap) Set(k int, vals ...int) error {
    s, ok := d.data[k]
    if !ok {
        s = make([]int, 0, d.nmax) // allocate slice of given length
    }
    // optionally check for nil-values + ensure we're not exceeding the nmax
    checked := make([]int, 0, len(vals))
    for i := range vals {
        if vals[i] != 0 {
            checked = append(checked, vals[i])
        }
    }
    if len(s) + len(checked) > d.nmax {
        return errors.New("max capacity exceeded")
    }
    s = append(s, checked...) // append values
    d.data[k] = s // update map
    return nil
}

这减少了不必要的内存(重新)分配调用。它还确保我可以在 O(1) 操作中获取映射中任何 slice 的长度,而不必担心 nil 值:

myData := New(10)
fmt.Println(myData.Set(4, 1, 2, 3, 4))
fmt.Println(len(myData.Get(4))) // 4
fmt.Println(cap(myData.Get(4))) // 10
// nil-values are filtered out
myData.Set(4, 5, 6, 7, 0, 0, 0, 0)
fmt.Println(len(myData.Get(4))) // 7
fmt.Println(cap(myData.Get(4))) // 10
// exceeding capacity of 10
fmt.Println(myData.Set(4, 8, 9, 10, 11)) // max capacity exceeded

工作demo


可以使用数组而不是 slice 来管理容量,但这确实需要您手动跟踪要开始附加值的索引/偏移量。一般来说,你不要在 golang 中使用数组,以免在非常非常特殊的情况下。在这种情况下,我只会选择带有固定帽的 slice 。这样做的好处是,例如,您可以拥有不同长度的 slice 。结果也很容易测试,因为像这样的类型很适合用接口(interface)类型替换它

type DataContainer interface {
    Get(k int) []int
    Set(k int, vals ...int) error
    Declare(k, capacity int) error // error if k is already in use?
}

关于go - 如何分配内存以映射指向golang中的 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52599876/

相关文章:

ios - 过度释放一个对象,应用程序不会崩溃

memory-management - 在ARMv8中,如果全局页表项在不同进程之间发生冲突会发生什么?

heroku - 如何使用子目录中的主包将 Go 应用程序部署到 Heroku?

go - 如何使用模板组织Golang WebApp?

go - 为什么 %v 为嵌套结构打印意外值?

optimization - GMSPolyline 非常大的内存峰值

python - 在 Python 中拆分字符串的最有效方法

iphone - 使用仪器进行内存分析

go - 将 map 分配给 Golang 中的 map

python - 优化Python在层次字典中的键搜索