gpt4 book ai didi

go - 为什么在预分配的 slice 上追加比索引更快?

转载 作者:IT王子 更新时间:2023-10-29 00:52:00 25 4
gpt4 key购买 nike

我编写了以下 Go 基准测试(Go1.9.2、Linux amd64)来测试索引与 append :

func BenchmarkIndex(b *testing.B) {
for i := 0; i < b.N; i++ {
existing := make([]int64, 1000, 1000)
init := make([]int64, 1000) // len 1000, cap 1000
for index, element := range existing {
init[index] = element
}
}
}

func BenchmarkAppend(b *testing.B) {
for i := 0; i < b.N; i++ {
existing := make([]int64, 1000, 1000)
init := make([]int64, 0, 1000) // len 0, capacity 1000
for _, element := range existing {
init = append(init, element)
}
}
}

得到如下结果:

goos: linux
goarch: amd64
BenchmarkIndex-4 1000000 2183 ns/op
BenchmarkAppend-4 1000000 1933 ns/op
PASS

我有点困惑为什么 append 似乎比索引到 slice 中表现得更好。它与省略范围内的 index 有什么关系吗?如果不是,那么 append 在幕后做了什么以使其比仅仅建立索引更快?

供引用,here is append's source .谢谢!

最佳答案

在电脑一上:

$ go test same_test.go -run=! -bench=. -benchmem -count=3
goos: linux
goarch: amd64
BenchmarkIndex-4 1000000 1290 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-4 1000000 1290 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-4 1000000 1288 ns/op 0 B/op 0 allocs/op
BenchmarkAppend-4 1000000 1299 ns/op 0 B/op 0 allocs/op
BenchmarkAppend-4 1000000 1302 ns/op 0 B/op 0 allocs/op
BenchmarkAppend-4 1000000 1301 ns/op 0 B/op 0 allocs/op
PASS
ok command-line-arguments 7.868s
$ go version
go version devel +38c725b148 Sun Nov 5 17:30:11 2017 +0000 linux/amd64
$

BenchmarkAppendBenchmarkIndex的区别是:

((1299+1302+1301) - (1290+1290+1288)) * 100 / (1290+1290+1288) =  +0.879%

它们是一样的。

在计算机二上:

$ go test same_test.go -run=! -bench=. -benchmem -count=3
goos: linux
goarch: amd64
BenchmarkIndex-8 2000000 706 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-8 2000000 713 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-8 2000000 710 ns/op 0 B/op 0 allocs/op
BenchmarkAppend-8 2000000 711 ns/op 0 B/op 0 allocs/op
BenchmarkAppend-8 2000000 718 ns/op 0 B/op 0 allocs/op
BenchmarkAppend-8 2000000 718 ns/op 0 B/op 0 allocs/op
PASS
ok command-line-arguments 12.945s
$ go version
go version devel +38c725b148 Sun Nov 5 17:30:11 2017 +0000 linux/amd64
$

BenchmarkAppendBenchmarkIndex的区别是:

((711+718+718) - (706+713+710)) * 100 / (706+713+710) =  +0.845%

它们是一样的。


让我们一次测量一件事,在预分配的 slice 上建立索引与追加,这避免了内存管理等混淆问题。

package main

import "testing"

func BenchmarkIndexing(b *testing.B) {
existing := make([]int64, 1000, 1000)
init := make([]int64, 1000) // len 1000, cap 1000
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
init = init[:cap(init)]
for index, element := range existing {
init[index] = element
}
}
}

func BenchmarkAppending(b *testing.B) {
existing := make([]int64, 1000, 1000)
init := make([]int64, 0, 1000) // len 0, capacity 1000
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
init = init[:0]
for _, element := range existing {
init = append(init, element)
}
}
}

输出:

$ go test same_test.go -run=! -bench=ing -benchmem -count=3
goos: linux
goarch: amd64
BenchmarkIndexing-4 2000000 736 ns/op 0 B/op 0 allocs/op
BenchmarkIndexing-4 2000000 735 ns/op 0 B/op 0 allocs/op
BenchmarkIndexing-4 2000000 735 ns/op 0 B/op 0 allocs/op
BenchmarkAppending-4 2000000 733 ns/op 0 B/op 0 allocs/op
BenchmarkAppending-4 2000000 733 ns/op 0 B/op 0 allocs/op
BenchmarkAppending-4 2000000 733 ns/op 0 B/op 0 allocs/op
PASS
ok command-line-arguments 13.303s
$ go version
go version devel +38c725b148 Sun Nov 5 17:30:11 2017 +0000 linux/amd64
$

BenchmarkAppendBenchmarkIndex的区别是:

((733+733+733) - (736+735+735)) * 100 / (736+735+735) =  −0.317%

它们是一样的。

关于go - 为什么在预分配的 slice 上追加比索引更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47124412/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com