跳到主要内容

CPU 性能优化

问题

Go 程序 CPU 使用率高怎么优化?如何定位热点函数?

答案

定位热点

# 1. 采集 CPU Profile
go test -bench=. -cpuprofile=cpu.prof
# 或在运行中采集
import _ "net/http/pprof"
# curl http://localhost:6060/debug/pprof/profile?seconds=30 > cpu.prof

# 2. 分析
go tool pprof cpu.prof
(pprof) top 10 # 前 10 热点函数
(pprof) list funcName # 查看源码级耗时
(pprof) web # 可视化调用图

常见 CPU 优化手段

手段场景
算法改进排序 → hash 查找
减少反射reflect → 代码生成
减少序列化JSON → Protobuf
字符串拼接+strings.Builder
正则预编译regexp.MustCompile 只编译一次
减少 GC 压力减少堆分配 → CPU 花在 GC 上的时间减少

实战例子

正则预编译

// ❌ 每次调用都编译正则
func validate(s string) bool {
re := regexp.MustCompile(`^\d+$`)
return re.MatchString(s)
}

// ✅ 编译一次,重复使用
var digitRe = regexp.MustCompile(`^\d+$`)

func validate(s string) bool {
return digitRe.MatchString(s)
}

JSON 替换

// 标准库 encoding/json 使用反射,CPU 密集
// 替换方案:
// 1. sonic (字节,最快)
import "github.com/bytedance/sonic"
sonic.Marshal(obj)

// 2. easyjson (代码生成,零反射)
// 3. jsoniter (兼容标准库 API)

PGO(Profile-Guided Optimization)

Go 1.21+ 支持基于 Profile 的编译优化:

# 1. 采集生产环境 profile
curl http://prod:6060/debug/pprof/profile?seconds=30 > default.pgo

# 2. 放在项目根目录,编译时自动使用
go build -pgo=auto ./cmd/server
# 通常提升 2-7% 的吞吐量

常见面试问题

Q1: pprof 的 flat vs cum 什么意思?

答案

  • flat:函数自身消耗的 CPU 时间(不算调用子函数)
  • cum:函数自身 + 调用的所有子函数消耗的总 CPU 时间

flat 高 = 函数本身计算密集,cumflat 低 = 问题在它调用的子函数中。

Q2: 什么是 PGO?

答案Profile-Guided Optimization。将生产环境的 CPU Profile 反馈给编译器,编译器据此优化热路径(如函数内联、分支预测)。Go 1.21 开始支持,放一个 default.pgo 文件在项目根目录即可。

相关链接