Golang 性能测试
发布时间:阅读数:103
前言
在开发的过程中,性能测试是必不可少的一个环节(其实我很多都没做过),对于程序能够承载的任务量和性能瓶颈可以能够有一个很好的把控(说是这么说),本次,以性能测试的方式来跑一下程序的性能情况!
一、概念
基准测试(benchmark)是 go testing 库提供的,用来度量程序性能,算法优劣的利器。
指定一个时间(默认是1秒),看测试对象在达到时间上限时,最多能被执行多少次和在此期间测试对象内存分配情况。
二、特点
基准测试的代码文件必须以_test.go结尾
基准测试的函数必须以Benchmark开头
基准测试函数必须接受一个指向Benchmark类型的指针作为唯一参数
基准测试函数不能有返回值
b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰
最后的for循环很重要,被测试的代码要放到循环里
b.N是基准测试框架提供的,表示循环的次数
三、常用API
b.StopTimer()
b.StartTimer()
b.ResetTimer()
b.Run(name string, f func(b *B))
b.RunParallel(body func(*PB))
b.ReportAllocs()
b.SetParallelism(p int)
b.SetBytes(n int64)
testing.Benchmark(f func(b *B)) BenchmarkResult
四、操作的命令
go test -bench=BenchmarkFoo
go test -bench=.
// 加上 -bench= 测试名字, .表示运行所有的基准测试,名字可用正则。
go test -bench=BenchmarkFoo -benchtime=5s/10000x
// 加上 -benchtime 设置时间,s表示秒,x表示执行次数
go test -bench=BenchmarkFoo -benchtime=5s -count=3
// 加上 -count 表示几次测试
go test -bench=. -benchmem
// 加上 -benchmem 查看内存
go test -bench=. -benchmem -cpuprofile profile.out
go test -bench=. -benchmem -memprofile memprofile.out
go tool pprof profile.out
go tool pprof memprofile.out
// 结合 pprof 输出查看 cpu和内存。
五、使用的方式
串行
func BenchmarkFoo(b *testing.B) {
for i:=0; i<b.N; i++ {
dosomething()
}
}
并行
func BenchmarkFoo(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
dosomething()
}
})
}
并行的goroutine个数是默认等于runtime.GOMAXPROCS(0)。
释义:创建P个goroutine之后,再把b.N打散到每个goroutine上执行
增大goroutine的个数,使用 b.SetParallelism(p int)
func BenchmarkFoo(b *testing.B) {
b.SetParallelism(10)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
dosomething()
}
})
}
// 原理: 最终goroutine个数 = 形参p的值 * runtime.GOMAXPROCS(0)
numProcs := b.parallelism * runtime.GOMAXPROCS(0)
StartTimer()、StopTimer()、ResetTimer()
init(); // 初始化工作
b.ResetTimer()
for i:=0; i<b.N; i++ { dosomething1() }
b.StopTimer()
otherWork(); // 例如做一些转换工作
b.StartTimer()
for i:=0; i<b.N; i++ { dosomething2() }
方式二
init(); // 初始化工作
b.ResetTimer()
for i:=0; i<b.N; i++ {
flag := dosomething()
if flag {
b.StopTimer()
} else {
b.StartTimer()
}
}
StartTimer()、ResetTimer() 都是记录当前时间为开始时间 和 内存分配情况,不过 ResetTimer()多了清空重置操作。
StopTimer() 累计记录执行的时间(当前时间 - 记录的开始时间),累计记录内存分配次数和分配字节数
Run()
表驱动法
func BenchmarkRR(b *testing.B) {
tests := []struct {
keyLength int
}{
{keyLength: 16},
{keyLength: 32},
}
for _, t := range tests {
name := fmt.Sprintf("%vKeyLength", t.keyLength)
b.Run(name, func(b *testing.B) {
dosomething(b, t.keyLength)
})
}
}
六、例子
fib.go
// 斐波那契数列
func fib(n int) int {
if n < 2 {
return n
}
return fib(n-1) + fib(n-2)
}
func sum(a, b int) int {
return a + b
}
fib_test.go
import "testing"
func BenchmarkFib10(b *testing.B) {
for n := 0; n < b.N; n++ {
fib(10)
}
}
func BenchmarkFib20(b *testing.B) {
for n := 0; n < b.N; n++ {
fib(20)
}
}
func BenchmarkSum(b *testing.B) {
for n := 0; n < b.N; n++ {
sum(1, 2)
}
使用正则
$ go test -bench=. .
使用-benchting
使用-benchting 的x单位
$ go test -bench=^BenchmarkFib20 -benchtime=3s
使用-count
根据前面的,多次运行,寻找理想值
$ go test -bench=^BenchmarkFib20 -benchtime=3s -count=10