Golang切片附加vs分配性能

问题描述 投票:7回答:2

为了使切片附加操作更快,我们需要分配足够的容量。有两种方法可以追加切片,这是代码:

func BenchmarkSliceAppend(b *testing.B) {
    a := make([]int, 0, b.N)
    for i := 0; i < b.N; i++ {
        a = append(a, i)
    }
}

func BenchmarkSliceSet(b *testing.B) {
    a := make([]int, b.N)
    for i := 0; i < b.N; i++ {
        a[i] = i
    }
}

结果是:

BenchmarkSliceAppend-4 200000000 7.87 ns / op 8 B / op 0 allocs / op

BenchmarkSliceSet-4 300000000 5.76 ns / op 8 B / op

a[i] = ia = append(a, i)快,我想知道为什么?

performance go slice
2个回答
7
投票

a[i] = i只是将值i分配给a[i]。这不是追加,它只是一个简单的assignment

现在附加:

a = append(a, i)

理论上会发生以下情况:

  1. 这称为内置append()函数。为此,它首先必须复制a切片(切片标头,支持数组不是标头的一部分),并且必须为可变参数创建一个临时切片,该参数将包含值i
  2. 然后它必须重新组合a,如果它有足够的容量(在你的情况下),如a = a[:len(a)+1] - 这涉及将新切片分配给a内的append()。 (如果a没有足够的容量来“追加”附加,则必须分配一个新数组,复制切片的内容,然后执行assign / append - 但这不是这里的情况。 )
  3. 然后将i分配给a[len(a)-1]
  4. 然后从append()返回新切片,并将此新切片分配给局部变量a

与简单的任务相比,这里发生了很多事情。即使这些步骤中的许多步骤被优化和/或内联,作为将i分配给切片的元素的最小附加,切片类型的局部变量a(其是切片头部)必须在每个周期中更新。环。

推荐阅读:The Go Blog: Arrays, slices (and strings): The mechanics of 'append'


4
投票

由于此问题已经发布,似乎已经引入了Go编译器或运行时的一些改进,所以现在(Go 1.10.1append和索引直接赋值之间没有显着差异。

另外,由于OOM恐慌,我不得不稍微改变你的基准。

package main

import "testing"

var result []int

const size = 32

const iterations = 100 * 1000 * 1000

func doAssign() {
    data := make([]int, size)
    for i := 0; i < size; i++ {
        data[i] = i
    }
    result = data
}

func doAppend() {
    data := make([]int, 0, size)
    for i := 0; i < size; i++ {
        data = append(data, i)
    }
    result = data
}

func BenchmarkAssign(b *testing.B) {
    b.N = iterations
    for i := 0; i < b.N; i++ {
        doAssign()
    }
}

func BenchmarkAppend(b *testing.B) {
    b.N = iterations
    for i := 0; i < b.N; i++ {
        doAppend()
    }
}

结果:

➜  bench_slice_assign go test -bench=Bench .
goos: linux
goarch: amd64
BenchmarkAssign-4       100000000           80.9 ns/op
BenchmarkAppend-4       100000000           81.9 ns/op
PASS
ok      _/home/isaev/troubles/bench_slice_assign    16.288s
© www.soinside.com 2019 - 2024. All rights reserved.