Go语言性能分析

一、benchmark基准测试
1. 性能分析

Go语言优化代码的过程中,需要评估代码的性能如何。Go标准库内置的testing测试框架提供了基准测试(benchmark)工具,可以很容易地对某一段代码进行性能测试。

2. 快速开始

(1)初始化模块:go mod init benchmark_demo

(2)需要测试的函数,这里以求解斐波那契数列为例:

// benchmark_demo/fib.go
package main

// 需要测试的函数
func fib(n int) int {
	if n <= 1 {
		return n
	}
	return fib(n-2) + fib(n-1)
}

​ (3)编写测试代码,实现benchmark示例:

// benchmark_demo/fib_test.go
package main
import "testing"
// BenchmarkFib 使用Benchmark工具对函数进行测试
func BenchmarkFib(b *testing.B) {
	for n := 0; n < b.N; n ++ {
		fib(30)
	}
}

​ (4)通过命令换运行

go test -bench .

​ (5)运行结果

$ go test -bench .
goos: windows
goarch: amd64
pkg: benchmark_demo
cpu: Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz
BenchmarkFib-8               264           4499835 ns/op
PASS
ok      benchmark_demo  1.950s

​ - benchmark与单元测试用例一样,都位于xxx_test.go文件中。

	- 函数名以`Benchmark`开头,参数是`b *test.B`。
3. benchmark的工作原理

(1)b *test.B参数:b参数有个属性b.N,表示测试用例需要运行的次数。b.N的值对于每个用例是不同的。如果该用例能在1s内完成,则b.N的值会增加,再次执行。

(2)指定CPU核数,上面运行结果的第5行:BenchmarkFib-8 表示测试用使用了8个CPU核数,可以通过-cpu参数改变,例如:

$ go test -bench . -cpu=4

​ 改变CPU的核数对结果几乎没有影响,因为测试是串行的。

(3)运行用例,

​ a. 运行当前package内的用例:go test xxxgo test .

​ b. 运行子package内的用例:go test example/xxxgo test ./xxx

go test命令默认不运行benchmark用例,**如果需要运行benchmark用例,则需要加上-bench参数。**对于benchmark用例,函数名需要以Benchmark开头,参数为*testing.B

4. 提高准确度

​ 性能测试受环境的影响很大,为了保证测试的可重复性,在进行性能测试时,尽可能地保持测试环境的稳定。

​ (1)提高测试的准确度的一个重要手段就是增加测试次数,可以使用-benchtime-count参数达到目的。

​ benchmark 的默认时间是 1s,那么我们可以使用 -benchtime 指定为 5s。例如:

$ go test -bench='Fib$' -benchtime=5s .
goos: darwin
goarch: amd64
pkg: example
BenchmarkFib-8              1033           5769818 ns/op
PASS
ok      example 6.554s

​ 结果调用了1033次测试用例,总耗时6.554s,包含用例的编译、执行、销毁。

-benchtime 的值除了是时间外,还可以是具体的次数。例如,执行 30 次可以用-benchtime=30x

$ go test -bench='Fib$' -benchtime=50x .
goos: darwin
goarch: amd64
pkg: example
BenchmarkFib-8                50           6121066 ns/op
PASS
ok      example 0.319s

-count 参数可以用来设置 benchmark 的轮数。例如,进行 3 轮 benchmark。

$ go test -bench='Fib$' -benchtime=5s -count=3 .
goos: darwin
goarch: amd64
pkg: example
BenchmarkFib-8               975           5946624 ns/op
BenchmarkFib-8              1023           5820582 ns/op
BenchmarkFib-8               961           6096816 ns/op
PASS
ok      example 19.463s
5. 内存分配情况

-benchmem 参数可以度量内存分配的次数。内存分配次数也性能也是息息相关的,例如不合理的切片容量,将导致内存重新分配,带来不必要的开销。


二、pprof性能测试

1.性能分析的类型
1.1 CPU 性能分析

CPU 性能分析(CPU profiling) 是最常见的性能分析类型。

启动 CPU 分析时,运行时(runtime) 将每隔 10ms 中断一次,记录此时正在运行的协程(goroutines) 的堆栈信息。

程序运行结束后,可以分析记录的数据找到最热代码路径(hottest code paths)。

Compiler hot paths are code execution paths in the compiler in which most of the execution time is spent, and which are potentially executed very often.
What’s the meaning of “hot codepath”

一个函数在性能分析数据中出现的次数越多,说明执行该函数的代码路径(code path)花费的时间占总运行时间的比重越大。

1.2 内存性能分析

内存性能分析(Memory profiling) 记录堆内存分配时的堆栈信息,忽略栈内存分配信息。

内存性能分析启用时,默认每1000次采样1次,这个比例是可以调整的。因为内存性能分析是基于采样的,因此基于内存分析数据来判断程序所有的内存使用情况是很困难的。

1.3 阻塞性能分析

阻塞性能分析(block profiling) 是 Go 特有的。

阻塞性能分析用来记录一个协程等待一个共享资源花费的时间。在判断程序的并发瓶颈时会很有用。阻塞的场景包括:

  • 在没有缓冲区的信道上发送或接收数据。
  • 从空的信道上接收数据,或发送数据到满的信道上。
  • 尝试获得一个已经被其他协程锁住的排它锁。

一般情况下,当所有的 CPU 和内存瓶颈解决后,才会考虑这一类分析。

1.4 锁性能分析

锁性能分析(mutex profiling) 与阻塞分析类似,但专注于因为锁竞争导致的等待或延时。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值