【发布时间】:2015-08-12 01:27:26
【问题描述】:
这个问题是关于访问数组和切片元素的速度,而不是关于将它们作为参数传递给函数的效率。
我希望 arrays 在大多数情况下比 slices 更快,因为 slice 是一种描述数组连续部分的数据结构,因此可能会有额外的访问切片元素(间接访问其底层数组的元素)时涉及的步骤。
所以我写了一个小测试来对一批简单的操作进行基准测试。有 4 个基准函数,前 2 个测试 global 切片和全局数组,另外 2 个测试 local 切片和本地数组:
var gs = make([]byte, 1000) // Global slice
var ga [1000]byte // Global array
func BenchmarkSliceGlobal(b *testing.B) {
for i := 0; i < b.N; i++ {
for j, v := range gs {
gs[j]++; gs[j] = gs[j] + v + 10; gs[j] += v
}
}
}
func BenchmarkArrayGlobal(b *testing.B) {
for i := 0; i < b.N; i++ {
for j, v := range ga {
ga[j]++; ga[j] = ga[j] + v + 10; ga[j] += v
}
}
}
func BenchmarkSliceLocal(b *testing.B) {
var s = make([]byte, 1000)
for i := 0; i < b.N; i++ {
for j, v := range s {
s[j]++; s[j] = s[j] + v + 10; s[j] += v
}
}
}
func BenchmarkArrayLocal(b *testing.B) {
var a [1000]byte
for i := 0; i < b.N; i++ {
for j, v := range a {
a[j]++; a[j] = a[j] + v + 10; a[j] += v
}
}
}
我多次运行测试,这是典型的输出 (go test -bench .*):
BenchmarkSliceGlobal 300000 4210 ns/op
BenchmarkArrayGlobal 300000 4123 ns/op
BenchmarkSliceLocal 500000 3090 ns/op
BenchmarkArrayLocal 500000 3768 ns/op
分析结果:
访问全局切片比访问全局数组稍慢,正如我所料:4210 vs 4123ns/op
但是访问本地切片比访问本地数组要快得多:3090 vs 3768ns/op
我的问题是:这是什么原因?
备注
我尝试改变以下内容,但没有改变结果:
- 数组/切片的大小(已尝试 100、1000、10000)
- 基准函数的顺序
- 数组/切片的元素类型(试过
byte和int)
【问题讨论】:
-
有几个因素会影响这样的微基准:边界检查、分配(堆、堆栈)、代码生成、窥视孔优化等。看看在不同条件下生成的程序集输出,如禁用边界检查或禁用优化。
-
有趣的是,如果您将pointer to array 添加到基准测试中,您会发现它们的性能与切片大致相同。
标签: arrays performance go benchmarking slice