为什么在循环中分配数组条目的速度较慢?

时间:2019-11-15 13:49:42

标签: go

我发现了这个奇怪的基准测试结果,这似乎表明如果不循环执行,分配数组元素的速度会更快。希望有人可以解释它。完整的Go代码在下面,基准BenchmarkDirectAssignment的运行速度似乎快十倍,即使它在做同样的事情:

package main

import "testing"

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

func BenchmarkDirectAssignment(b *testing.B) {
  arr := make([]int, 10)
  for n := 0; n < b.N; n++ {
    arr[0] = n
    arr[1] = n
    arr[2] = n
    arr[3] = n
    arr[4] = n
    arr[5] = n
    arr[6] = n
    arr[7] = n
    arr[8] = n
    arr[9] = n
  }
}
$ go test -bench=.
goos: windows
goarch: amd64
BenchmarkLoopAssignment-16              500000000                3.76 ns/op
BenchmarkDirectAssignment-16            2000000000               0.25 ns/op
PASS
ok      _/D_/go_benchmark       3.107s

我已经用Java和C#复制了此代码,并得到了相同的结果-直接分配总是更快。有谁知道为什么会这样?谢谢!

2 个答案:

答案 0 :(得分:5)

在第一个示例中,您有一个循环。每次触发至少要跳转1次+修改并检查运行变量。那是您分配作业的开销。

在第二个示例中,您对分配进行了硬编码。这些命令可以按顺序读取。无需跳转,计数或检查相关的间接费用。

但是值得指出的是,这种差异几乎不会发生:

https://ericlippert.com/2012/12/17/performance-rant/

无论如何您都不可以将案例2用于大型列表。至少不是某些自动代码创建的这一方面,

答案 1 :(得分:0)

第一个示例涉及很少的使用cpu内存的额外计算,然后才进行实际分配。 但是对于第二个示例,它是直接分配而无需更多计算。 正如其他答案所提到的,对于本示例案例而言,这并不重要,但是对于更复杂/更大的数据集,算法如何有效工作非常重要。

由于计算是相同的,因此上述结果对于其他编程语言也可能相同。

关于复杂性和big-O的一些好的说明,这可能会有所帮助 http://pages.cs.wisc.edu/~vernon/cs367/notes/3.COMPLEXITY.html