gpt4 book ai didi

testing - 去基准和 gc : B/op alloc/op

转载 作者:IT王子 更新时间:2023-10-29 01:01:43 26 4
gpt4 key购买 nike

基准代码:

func BenchmarkSth(b *testing.B) {
var x []int
b.ResetTimer()
for i := 0; i < b.N; i++ {
x = append(x, i)
}
}

结果:

BenchmarkSth-4    50000000    20.7 ns/op    40 B/op    0 allocs/op 

问题:

  • 40 B/op 从何而来? (非常感谢任何追踪方式+说明)
  • 怎么可能有 40 个 B/op 而有 0 个分配?
  • 哪个会影响 GC,如何影响? (B/op 或 allocs/op)
  • 真的有可能使用 append 得到 0 B/op 吗?

最佳答案

The Go Programming Language Specification

Appending to and copying slices

The variadic function append appends zero or more values x to s of type S, which must be a slice type, and returns the resulting slice, also of type S.

append(s S, x ...T) S  // T is the element type of S

If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.

对于您的示例,平均而言,每个操作分配 [40, 41) 字节以在必要时增加 slice 的容量。使用摊销常数时间算法增加容量:直到 len 1024 增加到上限的 2 倍,然后增加到上限的 1.25 倍。平均而言,每个操作有 [0, 1) 个分配。

例如,

func BenchmarkMem(b *testing.B) {
b.ReportAllocs()
var x []int64
var a, ac int64
b.ResetTimer()
for i := 0; i < b.N; i++ {
c := cap(x)
x = append(x, int64(i))
if cap(x) != c {
a++
ac += int64(cap(x))
}
}
b.StopTimer()
sizeInt64 := int64(8)
B := ac * sizeInt64 // bytes
b.Log("op", b.N, "B", B, "alloc", a, "lx", len(x), "cx", cap(x))
}

输出:

BenchmarkMem-4      50000000            26.6 ns/op        40 B/op          0 allocs/op
--- BENCH: BenchmarkMem-4
bench_test.go:32: op 1 B 8 alloc 1 lx 1 cx 1
bench_test.go:32: op 100 B 2040 alloc 8 lx 100 cx 128
bench_test.go:32: op 10000 B 386296 alloc 20 lx 10000 cx 12288
bench_test.go:32: op 1000000 B 45188344 alloc 40 lx 1000000 cx 1136640
bench_test.go:32: op 50000000 B 2021098744 alloc 57 lx 50000000 cx 50539520

对于 op = 50000000

B/op = floor(2021098744 / 50000000) = floor(40.421974888) = 40

allocs/op = floor(57 / 50000000) = floor(0.00000114) = 0

阅读:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

'append' complexity

要使追加的 B/op(和 allocs/op)为零,请在追加之前分配一个具有足够容量的 slice 。

例如,使用 var x = make([]int64, 0, b.N),

func BenchmarkZero(b *testing.B) {
b.ReportAllocs()
var x = make([]int64, 0, b.N)
var a, ac int64
b.ResetTimer()
for i := 0; i < b.N; i++ {
c := cap(x)
x = append(x, int64(i))
if cap(x) != c {
a++
ac += int64(cap(x))
}
}
b.StopTimer()
sizeInt64 := int64(8)
B := ac * sizeInt64 // bytes
b.Log("op", b.N, "B", B, "alloc", a, "lx", len(x), "cx", cap(x))
}

输出:

BenchmarkZero-4     100000000           11.7 ns/op         0 B/op          0 allocs/op
--- BENCH: BenchmarkZero-4
bench_test.go:51: op 1 B 0 alloc 0 lx 1 cx 1
bench_test.go:51: op 100 B 0 alloc 0 lx 100 cx 100
bench_test.go:51: op 10000 B 0 alloc 0 lx 10000 cx 10000
bench_test.go:51: op 1000000 B 0 alloc 0 lx 1000000 cx 1000000
bench_test.go:51: op 100000000 B 0 alloc 0 lx 100000000 cx 100000000

请注意基准 CPU 时间从大约 26.6 ns/op 减少到大约 11.7 ns/op。

关于testing - 去基准和 gc : B/op alloc/op,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42172360/

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