赞
踩
目录
函数参数类型为*testing.B
测试函数名称必须以Benchmark 开头
执行基准测试时,需要添加-bench参数
运行所有基准测试函数
go test –bench=.*
编写一个对于for循环的基准测试
- func NewStringSlice(n int) []string {
- rand.Seed(time.Now().UnixNano())
- arr := make([]string, 0, n)
- for i := 0; i < n; i++ {
- arr = append(arr, strconv.Itoa(rand.Int()))
- }
-
- return arr
- }
-
-
- func BenchmarkStringSlice100(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewStringSlice(100)
- }
- }
-
- func BenchmarkStringSlice1000(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewStringSlice(1000)
- }
- }
-
- func BenchmarkStringSlice8000(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewStringSlice(8000)
- }
- }
-
- func BenchmarkStringSlice9000(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewStringSlice(9000)
- }
- }
-
- func BenchmarkStringSlice10000(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewStringSlice(10000)
- }
- }

运行所有BenchmarkStringSlice开头的基准测试函数:
go test -bench=^BenchmarkStringSlice -benchtime=5s .\testt\ -benchmem
结果如下:
- BenchmarkStringSlice100-16 512133 12192 ns/op 4191 B/op 101 allocs/op
- BenchmarkStringSlice1000-16 116264 49866 ns/op 40375 B/op 1001 allocs/op
- BenchmarkStringSlice8000-16 17469 341199 ns/op 323003 B/op 8001 allocs/op
- BenchmarkStringSlice9000-16 15597 383283 ns/op 363379 B/op 9001 allocs/op
- BenchmarkStringSlice10000-16 14016 425329 ns/op 403754 B/op 10001 allocs/op
- PASS
- 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
- func Fibonacci1(num int) int {
- if num < 1 {
- return 0
- }
-
- if num == 1 || num == 2 {
- return 1
- }
- return Fibonacci1(num-1) + Fibonacci1(num-2)
- }
Fibonacci2
- func Fibonacci2(num int) int {
- if num < 1 {
- return 0
- }
-
- backMap := make(map[int]int)
- return fib(backMap, num)
- }
-
- func fib(backMap map[int]int, num int) int {
- if num == 1 || num == 2 {
- return 1
- }
-
- if backMap[num] != 0 {
- return backMap[num]
- }
-
- backMap[num] = fib(backMap, num-1) + fib(backMap, num-2)
- return backMap[num]
- }

Fibonacci3
- func Fibonacci3(num int) int {
- if num < 1 {
- return 0
- }
-
- if num == 1 || num == 2 {
- return 1
- }
-
- left, right, res := 1, 1, 0
-
- for i := 3; i <= num; i++ {
- res = left + right
- left, right = right, res
- }
-
- return res
- }

如上都需要一个数值参数,获得一个数值,我们要做的就是计算在相同的入参情况下,三种算法的各自表现。
编写三种算法的基准测试基础函数
- func benchmarkFib1(b *testing.B, num int) {
- for i := 0; i < b.N; i++ {
- Fibonacci1(num)
- }
- }
-
- func benchmarkFib2(b *testing.B, num int) {
- for i := 0; i < b.N; i++ {
- Fibonacci2(num)
- }
- }
-
- func benchmarkFib3(b *testing.B, num int) {
- for i := 0; i < b.N; i++ {
- Fibonacci3(num)
- }
- }

另外编写外层调用,以入参为10举例:
- func BenchmarkFib10_1(b *testing.B) { benchmarkFib1(b, 10) }
- func BenchmarkFib10_2(b *testing.B) { benchmarkFib2(b, 10) }
- func BenchmarkFib10_3(b *testing.B) { benchmarkFib3(b, 10) }
想比较什么值,传不同的值即可。
第一波,验证下入参都为10时的各自效果:
- go test -bench=^BenchmarkFib10 -benchtime=10s .\testt\ -benchmem
-
- BenchmarkFib10_1-16 94737864 129.1 ns/op 0 B/op 0 allocs/op
- BenchmarkFib10_2-16 75052676 163.5 ns/op 0 B/op 0 allocs/op
- BenchmarkFib10_3-16 1000000000 1.272 ns/op 0 B/op 0 allocs/op
- PASS
- ok awesomeProject/testt 26.942s
就结果而言,算法3明显更优,能支持的执行次数更大,每次调用时间更短,百倍数量级差异。
接着,验证下入参都为50时的各自效果。由于传入数值越大消耗时间就越长,因此为得到更准确的结果,我们将-benchtime调大:
- go test -bench=^BenchmarkFib50 -benchtime=50s .\testt\ -benchmem
-
- BenchmarkFib50_1-16 1 70255751500 ns/op 2360 B/op 8 allocs/op
- BenchmarkFib50_2-16 18577252 9417 ns/op 2401 B/op 9 allocs/op
- BenchmarkFib50_3-16 706275607 81.14 ns/op 0 B/op 0 allocs/op
- PASS
- 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 。举例如下:
- func BenchmarkFibParallel10_1(b *testing.B) {
- b.SetParallelism(2)
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- Fibonacci1(10)
- }
- })
- }
执行:
- go test -bench=^BenchmarkFibParallel10 -benchtime=10s .\testt\ -benchmem -cpu=1
-
- BenchmarkFibParallel10_1 74194387 310.1 ns/op 0 B/op 0 allocs/op
- BenchmarkFibParallel10_2 71352631 165.9 ns/op 0 B/op 0 allocs/op
- BenchmarkFibParallel10_3 1000000000 1.203 ns/op 0 B/op 0 allocs/op
- PASS
- ok awesomeProject/testt 37.271s
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。