详解Golang程序性能优化利器PGO(一):基础介绍与应用

发表时间: 2023-08-12 18:04

软件开发过程中,性能优化是不可或缺的一部分。无论是在Web服务、数据处理系统还是实时通信中,良好的性能都是至关重要的。Golang 从1.20版版本开始引入的 Profile Guided Optimization(PGO)机制能够帮助更好地优化 Go 程序的性能。

什么是 Profile Guided Optimization(PGO)?

编译器在编译程序的时候会对程序做很多优化,例如通过分析程序源代码就可以实现的 inline optimization(内联优化)、escape analysis(逃逸分析)、constant propagation(常数传播)等优化手段。但是还有一些优化手段是无法通过分析源代码来实现的,例如一个函数里有很多条件分支语句,我们会希望编译器自动优化条件分支顺序,来加快条件分支的判断,提升程序性能。但是,编译器是不知道知道实际业务场景中每个条件分支进入的次数情况的,因为这个和程序的输入有关,所以编译出的程序就没办法在具体的应用场景中达到最佳性能。在这种场景下,PGO 就能发挥很大的作用了。

Profile Guided Optimization(PGO ),也可以被称为 feedback-directed optimization (FDO),是 Go 编译器的一种优化技术,通过分析程序运行时的行为数据来优化程序的性能。PGO 工具在编译过程中收集程序运行时的数据,然后利用这些数据对程序进行针对性的优化。这个过程的实现步骤如下:

  1. 在程序运行时,使用 profiling 工具采集 profile 数据。
  2. 根据采集到的 profile 数据,对程序进行重新编译。
  3. 在重新编译后的程序中,再次采集 profile 数据,并重复步骤2,直到程序达到理想的性能。

关于性能的提升情况,Golang 官方给出的数据是,在 Go 1.21中,一组具有代表性的 Go 程序的基准测试表明,使用 PGO 构建可以提高大约2-7%的性能。随着 Golang 对 PGO的不断优化,对性能的提升作用相信也会越来越大。

使用示例

可以通过 net/http/pprof 包生成的文件作为 profile 文件,示例如下:

package mainimport (	"fmt"	"net/http"	_ "net/http/pprof")func IndexHandler(w http.ResponseWriter, r *http.Request) {	fmt.Fprintln(w, "hello world")}func main() {	http.HandleFunc("/test", IndexHandler)	http.ListenAndServe(":8000", nil)}

需要导入 net/http/pprof 这个库,这个库会生成用于采集 profile 文件的接口,这里使用 /debug/pprof/profile 接口,通过请求这个接口来获取程序运行时的数据。

1、 采集 profile 数据

访问
http://localhost:8000/debug/pprof/profile?seconds=30,这里的意思是采集30秒的数据,期间需要访问程序提供的功能接口,采集完成后将数据保存到程序主目录下,命名为 default.pgo(编译的时候,设置 -pgo 选项的值为 auto,会自动查找到此文件,使用起来更方便)

2、编译时启用 PGO 优化

编译的时候带上 -pgo 参数并且将值设置为 auto(也可以指定具体的文件),如下:

$ go build -pgo=auto -o markdown.withpgo

Golang 官方推荐使用 auto ,并且把 default.pgo 文件存放在程序主目录下维护,以方便项目的其他开发者使用 default.pgo 来对程序做性能优化。因为 PGO 是从 Go 1.20 开始引入的,所以需要将 Golang 升级到 1.20 及以上。