将项目添加到数组/切片而不消耗太多内存

问题描述 投票:0回答:1

第一次实施

我有这个功能。输入是

uint8
字节的切片。此函数在每个
255
字节后插入一个等于
0xff
3
值的新字节。

func ApplyAlpha(pix []uint8) []uint8 {
    l := 0
    for i := 0; i < len(pix); i++ {
        l++
        if l%3 == 0 && i+1 < len(pix) {
            // Insert alpha at the current position
            pix = append(pix[:i+1], append([]byte{255}, pix[i+1:]...)...)
            i++
        }
    }
    return pix
}

第二次实施

优化了吗?

为了优化功能,我可以这样重写:

func ApplyAlpha(pix []uint8) []uint8 {
    newPix := make([]uint8, len(pix)/3*4, len(pix)/3*4)
    l := 0
    for i := 0; i < len(pix); i++ {
        newPix[l] = pix[i]
        l++
        if (i+1)%3 == 0 {
            // Insert alpha at the current position
            newPix[l] = 255
            l++
        }
    }
    pix = newPix
    return pix
}

问题

第一种实现方式和第二种实现方式都有缺点:

  • 由于
    append
    调用,第一次实现的成本很高。
  • 第二个实现由于声明了一个全新的切片而消耗了大量内存。

问题

有什么我不知道的技巧或解决方法吗?进一步优化实施?

go optimization insert append slice
1个回答
0
投票

正如@PaulHankin 评论的那样:

最佳方法是确保

pix
从一开始就具有足够的
cap
以允许调整大小就地工作,然后您可以就地调整大小并将字节移动到正确的位置(例如:通过向后迭代通过切片)。

也许我们可以通过以下方式进一步优化:

func ApplyAlpha(pix []uint8) []uint8 {
    newLen := len(pix) / 3 * 4
    if newLen <= cap(pix) {
        pix = pix[:newLen]
    } else {
        pix = append(pix, make([]uint8, newLen-len(pix))...)
    }

    // number of original pixels (without the alpha channel)
    l := len(pix)/4*3 - 1

    // Work backward to avoid overwriting data
    for i := len(pix) - 1; i >= 0; i-- {
        if (i+1)%4 == 0 {
            pix[i] = 255
        } else {
            pix[i] = pix[l]
            l--
        }
    }
    return pix
}
© www.soinside.com 2019 - 2024. All rights reserved.