Go语言benchmark与pprof入门 | 青训营

71 阅读2分钟

以我不多的开发经验来看(很主观,欢迎讨论),后端开发者在学会和各种数据库(关系型MySQL和非关系型NoSQL等)交互(Repository层)、了解各种常见的后端架构(Service层,尤其是云原生时代的分布式微服务架构)、处理好和前端的对齐(Controller层)后,基本上在后端开发的职业路径就到头了。之后可能就分化成数据工程师、架构工程师、算法工程师、网络工程师等等不同细分职业。

但性能优化似乎仍属于后端工程师必不可少的通用技能之一,而在Golang中最常用到的优化评估工具便是benchmark和pprof。本篇文章将逐一介绍二者的基本用法。

benchmark

以一个常见的性能优化技巧为例,在提前知晓切片slice的最大容量capacity时,在make初始化时预分配capacity能够降低运行时间并减少扩容时的内存拷贝。待测试代码如下:

 // target_file.go
 package main
 ​
 func PreAllocatedSlice(size int) {
     s := make([]int, 0, size)
     for i := 0; i < size; i++ {
         s = append(s, i)
     }
 }
 ​
 func NotPreAllocatedSlice(size int) {
     s := make([]int, 0)
     for i := 0; i < size; i++ {
         s = append(s, i)
     }
 }

benchmark(基准测试)以如下形式写在测试文件target_file_test.go

 package main
 ​
 import "testing"
 ​
 func BenchmarkPreAllocatedSlice(b *testing.B) {
     for i := 0; i < b.N; i++ {
         PreAllocatedSlice(100)
     }
 }
 ​
 func BenchmarkNotPreAllocatedSlice(b *testing.B) {
     for i := 0; i < b.N; i++ {
         NotPreAllocatedSlice(100)
     }
 }

使用如下命令串行运行该文件夹下所有基准测试

 go test -benchmem -bench .

运行结果如下图所示:

result.png

其中-8表示GOMAXPROCS=8进程使用最大CPU数,第二列表示b.N执行次数,第三列表示每次执行花费的时间,第四列表示每次执行申请了多大的内存,第五列表示每次执行申请了几次内存。

整体执行情况符合预期。

pprof

pprof通过读取profile.proto格式的采样数据,生成项目对CPU和内存的使用情况分析报告,并支持在网页上数据可视化,是用来分析程序性能的重要工具。

benchmark负责微观,pprof负责宏观,二者互补。

Golang自带pprof工具,但可视化需要Graphviz工具。

  1. Windows安装Graphviz下载地址:graphviz.org/download/

  2. 安装时需要选择添加到系统路径

  3. 然后需要在.../Graphviz/bin目录下执行dot.exe命令生成配置文件

以埋了雷的github.com/wolfogre/go…仓库代码为例,使用go run main.go把程序跑起来。

在另一个命令行页面中,使用如下命令在网页端可视化查看堆内存分配情况:

 go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"

结果如下,定位到问题函数Mouse.Steal

heap.png

查看Mouse.Steal代码实现:

 func (m *Mouse) Steal() {
     log.Println(m.Name(), "steal")
     max := constant.Gi
     for len(m.buffer)*constant.Mi < max {
         m.buffer = append(m.buffer, [constant.Mi]byte{})
     }
 }

发现第五行在反复申请内存,注释掉即可排除问题。

其余各种错误均可以通过替换URL(即"http://localhost:6060/debug/pprof/heap")后缀(把heap可以换成allocs, block, goroutine, heap, mutex, profile?seconds=10等)在网页端可视化页面定位问题,欢迎读者自由探索。