Go语言精进之路读书笔记第46条——为被测对象建立性能基准
46.1 性能基准测试在Go语言中是“一等公民”
性能基准测试在Go语言中和普通的单元测试一样被原生支持的,得到的是“一等公民”的待遇。
我们可以像对普通单元测试那样在*_test.go文件中创建被测对象的性能基准测试,每个以Benchmark前缀开头的函数都会被当作一个独立的性能基准测试。
46.2 顺序执行和并行执行的性能基准测试
#通过-benchtime手动指定b.N的值
go test -v -benchtime 5x -bench . sequential_test.go
#通过-count手动指定执行次数
go test -v -count 2 -bench . sequential_test.go
#通过-cpu手动指定GOMAXPROCS
go test -v -bench . paralell_test.go -cpu 2,4,8
go test -v -bench . paralell_test.go -cpu=2
1.顺序执行
var (
m map[int64]struct{} = make(map[int64]struct{}, 10)
mu sync.Mutex
round int64 = 1
)
func BenchmarkSequential(b *testing.B) {
fmt.Printf("\ngoroutine[%d] enter BenchmarkSequential: round[%d], b.N[%d]\n",
tls.ID(), atomic.LoadInt64(&round), b.N)
defer func() {
atomic.AddInt64(&round, 1)
}()
for i := 0; i < b.N; i++ {
mu.Lock()
_, ok := m[round]
if !ok {
m[round] = struct{}{}
fmt.Printf("goroutine[%d] enter loop in BenchmarkSequential: round[%d], b.N[%d]\n",
tls.ID(), atomic.LoadInt64(&round), b.N)
}
mu.Unlock()
}
fmt.Printf("goroutine[%d] exit BenchmarkSequential: round[%d], b.N[%d]\n",
tls.ID(), atomic.LoadInt64(&round), b.N)
}
2.并行执行
var (
m map[int64]int = make(map[int64]int, 20)
mu sync.Mutex
round int64 = 1
)
func BenchmarkParalell(b *testing.B) {
fmt.Printf("\ngoroutine[%d] enter BenchmarkParalell: round[%d], b.N[%d]\n",
tls.ID(), atomic.LoadInt64(&round), b.N)
defer func() {
atomic.AddInt64(&round, 1)
}()
b.RunParallel(func(pb *testing.PB) {
id := tls.ID()
fmt.Printf("goroutine[%d] enter loop func in BenchmarkParalell: round[%d], b.N[%d]\n", tls.ID(), atomic.LoadInt64(&round), b.N)
for pb.Next() {
mu.Lock()
_, ok := m[id]
if !ok {
m[id] = 1
} else {
m[id] = m[id] + 1
}
mu.Unlock()
}
mu.Lock()
count := m[id]
mu.Unlock()
fmt.Printf("goroutine[%d] exit loop func in BenchmarkParalell: round[%d], loop[%d]\n", tls.ID(), atomic.LoadInt64(&round), count)
})
fmt.Printf("goroutine[%d] exit BenchmarkParalell: round[%d], b.N[%d]\n",
tls.ID(), atomic.LoadInt64(&round), b.N)
}
46.3 使用性能基准比较工具
benchcmp已废弃,官方推荐用经过统计学方法处理的benchstat。
46.4 排除额外干扰,让基准测试更精确
使用testing.B提供的定时器操作方法排除额外干扰,让基准测试更精确,但不要在RunParallel中使用ResetTimer、StartTimer、StopTimer,因为它们具有全局副作用。