如何分配内存以映射指向golang中的切片

时间:2018-10-01 22:44:33

标签: go optimization memory-management

是否有一种方法来分配一个映射存储器,该存储器最多具有Nmax个键,该键指向最大长度为Nmax的切片?

我目前仅通过make(map[int][]int,Nmax)指定最大密钥数,但是我不确定如何告诉Go每个切片的最大长度为Nmax,因为我不知道什么键是先验的。

我基本上有一堆人口为整数的网站。我使用地图跟踪给定人口N的站点数。我程序中的瓶颈似乎是runtime.memmove,我猜想这是由于不断调整地图所指向切片的大小而引起的。

2 个答案:

答案 0 :(得分:1)

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

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)操作获取映射中任何切片的长度,而不必担心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


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

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?
}

答案 1 :(得分:0)

您对问题的描述含糊不清,您没有提供代码来说明您的问题。

如果地图切片容量等于零,则将其设置为Nmax。例如,

package main

import "fmt"

func main() {
    Nmax := 42

    m := make(map[int][]int, Nmax)

    k, e := 7, 11
    v := m[k]
    if cap(v) == 0 {
        v = make([]int, 0, Nmax)
    }
    m[k] = append(v, e)

    v = m[k]
    fmt.Println(k, len(v), cap(v), v)

    fmt.Println(m)
}

游乐场:https://play.golang.org/p/csoUCUvVDAp

输出:

7 1 42 [11]
map[7:[11]]