在Golang开发中,性能分析是优化程序运行效率的关键步骤,pprof和benchmark是官方提供的核心性能分析工具,能够帮助开发者定位CPU、内存占用过高的问题,同时测试代码的基准性能表现,下面详细介绍相关工具的安装和使用方法。

pprof工具的安装与基础使用
pprof是Golang内置的性能分析工具,不需要额外安装,只要安装了Golang环境就会自带相关依赖。我们可以通过runtime/pprof包在代码中手动开启性能采样,也可以通过net/http/pprof包提供HTTP接口实时查看性能数据。
通过HTTP接口使用pprof
这种方式适合长期运行的服务类程序,只需要在代码中引入net/http/pprof包,不需要额外调用任何函数,该包会自动注册相关的性能分析路由。
package main
import (
"log"
"net/http"
// 引入pprof包,自动注册路由
_ "net/http/pprof"
)
func main() {
// 启动HTTP服务,默认会在/debug/pprof/路径下提供性能分析接口
log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}
程序启动后,我们可以通过浏览器访问http://127.0.0.1:8080/debug/pprof/查看基础的性能概览,也可以通过go tool pprof命令获取更详细的分析数据。比如查看CPU性能采样数据,执行以下命令:
go tool pprof http://127.0.0.1:8080/debug/pprof/profile?seconds=30
上述命令会采样30秒的CPU使用情况,采样完成后会进入交互模式,我们可以通过top命令查看占用CPU最高的函数,通过web命令生成调用关系图,前提是需要安装graphviz工具。
手动采样性能数据
对于非服务类的程序,我们可以通过runtime/pprof包手动开启CPU和内存的采样,将采样数据输出到文件中,后续再通过pprof工具分析。
package main
import (
"os"
"runtime/pprof"
"time"
)
func main() {
// 创建CPU采样文件
cpuFile, err := os.Create("cpu.pprof")
if err != nil {
panic(err)
}
defer cpuFile.Close()
// 开启CPU采样
pprof.StartCPUProfile(cpuFile)
defer pprof.StopCPUProfile()
// 模拟业务代码执行
time.Sleep(2 * time.Second)
businessFunc()
// 创建内存采样文件
memFile, err := os.Create("mem.pprof")
if err != nil {
panic(err)
}
defer memFile.Close()
// 写入内存采样数据
pprof.WriteHeapProfile(memFile)
}
func businessFunc() {
// 模拟耗时操作
var s []string
for i := 0; i < 100000; i++ {
s = append(s, "test")
}
}
采样完成后,执行go tool pprof cpu.pprof即可分析CPU采样数据,执行go tool pprof mem.pprof即可分析内存分配数据。
benchmark基准测试的使用方法
benchmark是Golang testing包提供的基准测试功能,用于测试函数的性能表现,比如单次执行耗时、内存分配情况等,同样不需要额外安装工具,只要Golang环境正常即可使用。
编写基准测试函数
基准测试函数的命名需要以Benchmark开头,参数为*testing.B,函数内部需要通过b.ResetTimer()重置计时器,排除准备阶段的耗时,循环执行测试逻辑,循环次数由框架自动控制。
package main
import (
"strings"
"testing"
)
// 测试字符串拼接的性能
func BenchmarkStringJoin(b *testing.B) {
// 重置计时器,排除准备阶段的耗时
b.ResetTimer()
for i := 0; i < b.N; i++ {
// 模拟字符串拼接操作
var s strings.Builder
for j := 0; j < 100; j++ {
s.WriteString("test")
}
_ = s.String()
}
}
// 测试切片追加的性能
func BenchmarkSliceAppend(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var s []string
for j := 0; j < 100; j++ {
s = append(s, "test")
}
}
}
运行基准测试并查看结果
在测试文件所在目录执行以下命令即可运行基准测试:
go test -bench=. -benchmem
其中-bench=.表示运行所有基准测试,-benchmem表示输出内存分配相关的统计信息。执行后输出结果示例如下:
goos: linux goarch: amd64 pkg: example/test cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz BenchmarkStringJoin-8 1000000 1234 ns/op 1024 B/op 1 allocs/op BenchmarkSliceAppend-8 800000 1567 ns/op 2048 B/op 2 allocs/op PASS ok example/test 2.345s
结果中1000000表示测试执行的次数,1234 ns/op表示每次操作的平均耗时,1024 B/op表示每次操作平均分配的内存,1 allocs/op表示每次操作的平均内存分配次数。
pprof与benchmark结合分析性能
我们可以先通过benchmark快速定位性能较差的函数,再通过pprof对该函数进行详细的性能采样,分析具体的性能瓶颈点。比如在benchmark中发现某个函数耗时较高,我们可以在该函数中加入pprof的采样逻辑,或者通过HTTP接口实时采样该函数的执行过程,查看函数内部的调用耗时分布,从而针对性地优化代码。
比如我们在benchmark测试的业务函数中加入内存采样逻辑,就可以明确看到该函数执行过程中的内存分配情况,判断是否存在不必要的内存分配,进而优化内存使用效率。
常见问题说明
- pprof采样时会对程序性能有一定影响,生产环境使用HTTP接口采样时建议设置合理的采样时长,避免影响正常业务。
- benchmark的测试结果会受机器负载影响,建议多次测试取平均值,保证结果的可参考性。
- 如果需要在本地查看pprof生成的调用图,需要先安装graphviz工具,不同系统的安装命令不同,Ubuntu系统可以执行
sudo apt install graphviz安装。