Interpretting benchmarks of preallocating a slice
我一直在试图理解使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import"testing" func BenchmarkNoPreallocate(b *testing.B) { for i := 0; i < b.N; i++ { // Don't preallocate our initial slice init := []int64{} init = append(init, 5) } } func BenchmarkPreallocate(b *testing.B) { for i := 0; i < b.N; i++ { // Preallocate our initial slice init := make([]int64, 0, 1) init = append(init, 5) } } |
对结果有点困惑:
1 2 3 4 5 | $ go test -bench=. -benchmem goos: linux goarch: amd64 BenchmarkNoPreallocate-4 30000000 41.8 ns/op 8 B/op 1 allocs/op BenchmarkPreallocate-4 2000000000 0.29 ns/op 0 B/op 0 allocs/op |
号
我有几个问题:
- 为什么在预分配基准案例中没有分配(它显示0个分配/op)?当然,我们正在进行预分配,但分配必须在某个时刻发生。
- 我想在第一个问题被回答之后,这可能会变得更清楚,但是预分配的情况怎么会这么快呢?我是否误解了这个基准?
小精灵
如果有什么不清楚的地方请告诉我。谢谢您!
Go有一个优化编译器。常量在编译时计算。变量在运行时计算。常量值可用于优化编译器生成的代码。例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package main import"testing" func BenchmarkNoPreallocate(b *testing.B) { for i := 0; i < b.N; i++ { // Don't preallocate our initial slice init := []int64{} init = append(init, 5) } } func BenchmarkPreallocateConst(b *testing.B) { const ( l = 0 c = 1 ) for i := 0; i < b.N; i++ { // Preallocate our initial slice init := make([]int64, l, c) init = append(init, 5) } } func BenchmarkPreallocateVar(b *testing.B) { var ( l = 0 c = 1 ) for i := 0; i < b.N; i++ { // Preallocate our initial slice init := make([]int64, l, c) init = append(init, 5) } } |
输出:
1 2 3 4 | $ go test alloc_test.go -bench=. -benchmem BenchmarkNoPreallocate-4 50000000 39.3 ns/op 8 B/op 1 allocs/op BenchmarkPreallocateConst-4 2000000000 0.36 ns/op 0 B/op 0 allocs/op BenchmarkPreallocateVar-4 50000000 28.2 ns/op 8 B/op 1 allocs/op |
号
另一组有趣的基准:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package main import"testing" func BenchmarkNoPreallocate(b *testing.B) { const ( l = 0 c = 8 * 1024 ) for i := 0; i < b.N; i++ { // Don't preallocate our initial slice init := []int64{} for j := 0; j < c; j++ { init = append(init, 42) } } } func BenchmarkPreallocateConst(b *testing.B) { const ( l = 0 c = 8 * 1024 ) for i := 0; i < b.N; i++ { // Preallocate our initial slice init := make([]int64, l, c) for j := 0; j < cap(init); j++ { init = append(init, 42) } } } func BenchmarkPreallocateVar(b *testing.B) { var ( l = 0 c = 8 * 1024 ) for i := 0; i < b.N; i++ { // Preallocate our initial slice init := make([]int64, l, c) for j := 0; j < cap(init); j++ { init = append(init, 42) } } } |
输出:
1 2 3 4 | $ go test peter_test.go -bench=. -benchmem BenchmarkNoPreallocate-4 20000 75656 ns/op 287992 B/op 19 allocs/op BenchmarkPreallocateConst-4 100000 22386 ns/op 65536 B/op 1 allocs/op BenchmarkPreallocateVar-4 100000 22112 ns/op 65536 B/op 1 allocs/op |
。