当前位置:   article > 正文

go单元测试之benchmark基准测试详解

go单元测试之benchmark基准测试详解

目录

与普通测试的区别

举例说明

指令与结果解读

性能比较

并行测试


 

与普通测试的区别

函数参数类型为*testing.B

测试函数名称必须以Benchmark 开头

执行基准测试时,需要添加-bench参数

运行所有基准测试函数

go test –bench=.*

举例说明

编写一个对于for循环的基准测试

  1. func NewStringSlice(n int) []string {
  2.     rand.Seed(time.Now().UnixNano())
  3.     arr := make([]string, 0, n)
  4.     for i := 0; i < n; i++ {
  5.         arr = append(arr, strconv.Itoa(rand.Int()))
  6.     }
  7.     return arr
  8. }
  9. func BenchmarkStringSlice100(b *testing.B) {
  10.     for i := 0; i < b.N; i++ {
  11.         NewStringSlice(100)
  12.     }
  13. }
  14. func BenchmarkStringSlice1000(b *testing.B) {
  15.     for i := 0; i < b.N; i++ {
  16.         NewStringSlice(1000)
  17.     }
  18. }
  19. func BenchmarkStringSlice8000(b *testing.B) {
  20.     for i := 0; i < b.N; i++ {
  21.         NewStringSlice(8000)
  22.     }
  23. }
  24. func BenchmarkStringSlice9000(b *testing.B) {
  25.     for i := 0; i < b.N; i++ {
  26.         NewStringSlice(9000)
  27.     }
  28. }
  29. func BenchmarkStringSlice10000(b *testing.B) {
  30.     for i := 0; i < b.N; i++ {
  31.         NewStringSlice(10000)
  32.     }
  33. }

运行所有BenchmarkStringSlice开头的基准测试函数:

go test -bench=^BenchmarkStringSlice -benchtime=5s .\testt\ -benchmem

结果如下:

  1. BenchmarkStringSlice100-16                512133             12192 ns/op            4191 B/op        101 allocs/op
  2. BenchmarkStringSlice1000-16               116264             49866 ns/op           40375 B/op       1001 allocs/op
  3. BenchmarkStringSlice8000-16                17469            341199 ns/op          323003 B/op       8001 allocs/op
  4. BenchmarkStringSlice9000-16                15597            383283 ns/op          363379 B/op       9001 allocs/op
  5. BenchmarkStringSlice10000-16               14016            425329 ns/op          403754 B/op      10001 allocs/op
  6. PASS
  7. ok      awesomeProject/testt    43.135s

指令与结果解读

BenchmarkStringSlice100-16结尾的数字16表示GOMAXPROCS的值

-bench=^BenchmarkStringSlice表示所执行的基准测试范围包括以IntSlice结尾的基准测试函数,如果是-bench=abc$则表示所有以abc结尾的基准测试函数

-benchtime=5s表示性能测试运行的时间,默认是1s(1秒是最小值),有时候为了产生更准确的结果,可以增加-benchtime参数,用来指定最小基准时间。

后面的.\testt\表示执行的是testt目录下的测试文件。

-benchmem参数可用来获取执行性能测试时的内存分配数据

【结果】

512133表示发生的调用次数
12192 ns/op表示512133次调用消耗的平均时间为12192纳秒
4191 B/op表示每次操作内存分配了4191字节
101 allocs/op表示每次操作进行的内存分配次数,为101次。

 

性能比较

当算法不同时,我们仅需要以不同的输入来比较不同算法的性能差异,举个例子平时常见的比较有两种:

1、同一个函数,将不同的入参输入,比较不同参数的效果
2、不同的函数,将相同的入参输入,比较各自的效果

显然,做性能比较就是后者,而前者是对一个函数在不同条件下的性能测试。

作者编写了如下三种斐波那契数列的算法实现:

Fibonacci1

  1. func Fibonacci1(num int) int {
  2.     if num < 1 {
  3.         return 0
  4.     }
  5.     if num == 1 || num == 2 {
  6.         return 1
  7.     }
  8.     return Fibonacci1(num-1) + Fibonacci1(num-2)
  9. }

Fibonacci2

  1. func Fibonacci2(num int) int {
  2.     if num < 1 {
  3.         return 0
  4.     }
  5.     backMap := make(map[int]int)
  6.     return fib(backMap, num)
  7. }
  8. func fib(backMap map[int]int, num int) int {
  9.     if num == 1 || num == 2 {
  10.         return 1
  11.     }
  12.     if backMap[num] != 0 {
  13.         return backMap[num]
  14.     }
  15.     backMap[num] = fib(backMap, num-1) + fib(backMap, num-2)
  16.     return backMap[num]
  17. }

Fibonacci3

  1. func Fibonacci3(num int) int {
  2.     if num < 1 {
  3.         return 0
  4.     }
  5.     
  6.     if num == 1 || num == 2 {
  7.         return 1
  8.     }
  9.     
  10.     left, right, res := 1, 1, 0
  11.     for i := 3; i <= num; i++ {
  12.         res = left + right
  13.         left, right = right, res
  14.     }
  15.     return res
  16. }

如上都需要一个数值参数,获得一个数值,我们要做的就是计算在相同的入参情况下,三种算法的各自表现。

编写三种算法的基准测试基础函数

  1. func benchmarkFib1(b *testing.B, num int) {
  2.     for i := 0; i < b.N; i++ {
  3.         Fibonacci1(num)
  4.     }
  5. }
  6. func benchmarkFib2(b *testing.B, num int) {
  7.     for i := 0; i < b.N; i++ {
  8.         Fibonacci2(num)
  9.     }
  10. }
  11. func benchmarkFib3(b *testing.B, num int) {
  12.     for i := 0; i < b.N; i++ {
  13.         Fibonacci3(num)
  14.     }
  15. }

另外编写外层调用,以入参为10举例:

  1. func BenchmarkFib10_1(b *testing.B) { benchmarkFib1(b, 10) }
  2. func BenchmarkFib10_2(b *testing.B) { benchmarkFib2(b, 10) }
  3. func BenchmarkFib10_3(b *testing.B) { benchmarkFib3(b, 10) }

想比较什么值,传不同的值即可。

第一波,验证下入参都为10时的各自效果:

  1. go test -bench=^BenchmarkFib10 -benchtime=10s .\testt\ -benchmem
  2. BenchmarkFib10_1-16     94737864               129.1 ns/op             0 B/op          0 allocs/op
  3. BenchmarkFib10_2-16     75052676               163.5 ns/op             0 B/op          0 allocs/op
  4. BenchmarkFib10_3-16     1000000000               1.272 ns/op           0 B/op          0 allocs/op
  5. PASS
  6. ok      awesomeProject/testt    26.942s

就结果而言,算法3明显更优,能支持的执行次数更大,每次调用时间更短,百倍数量级差异。

接着,验证下入参都为50时的各自效果。由于传入数值越大消耗时间就越长,因此为得到更准确的结果,我们将-benchtime调大:

  1. go test -bench=^BenchmarkFib50 -benchtime=50s .\testt\ -benchmem
  2. BenchmarkFib50_1-16            1        70255751500 ns/op           2360 B/op          8 allocs/op
  3. BenchmarkFib50_2-16     18577252              9417 ns/op            2401 B/op          9 allocs/op
  4. BenchmarkFib50_3-16     706275607               81.14 ns/op            0 B/op          0 allocs/op
  5. PASS
  6. ok      awesomeProject/testt    369.285s

当入参为50,在相同的时间内(50秒),算法1只被调用了1次,而算法2则是其千万级的数量级优化,算法3更甚。

如果你对第二列被调用了多少次不敏感,或者没什么概念的话,可以这么理解:

执行入参为50的斐波那契数列,在给定的相同时间内,算法1只能执行1次,换句话说它没有机会再执行第二次了;

算法2在相同条件下却可以执行18577252次,消耗160秒;算法3干相同的活在相同条件下可以干706275607次,一共只花了70秒。

并行测试

即以并行的方式执行给定的基准测试。

b.RunParallel 会创建出多个goroutine,并将b.N分配给这些goroutine执行,其中goroutine数量的默认值为GOMAXPROCS。

如果想要增加非CPU受限(non-CPU-bound)基准测试的并行性, 那么可以在RunParallel之前调用 SetParallelism 。举例如下:

  1. func BenchmarkFibParallel10_1(b *testing.B) {
  2.     b.SetParallelism(2)
  3.     b.RunParallel(func(pb *testing.PB) {
  4.         for pb.Next() {
  5.             Fibonacci1(10)
  6.         }
  7.     })
  8. }

执行:

  1. go test -bench=^BenchmarkFibParallel10 -benchtime=10s .\testt\ -benchmem -cpu=1
  2. BenchmarkFibParallel10_1        74194387               310.1 ns/op             0 B/op          0 allocs/op
  3. BenchmarkFibParallel10_2        71352631               165.9 ns/op             0 B/op          0 allocs/op
  4. BenchmarkFibParallel10_3        1000000000               1.203 ns/op           0 B/op          0 allocs/op
  5. PASS
  6. ok      awesomeProject/testt    37.271s

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/339440
推荐阅读
相关标签
  

闽ICP备14008679号