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 高 = 函数本身计算密集,cum 高 flat 低 = 问题在它调用的子函数中。
Q2: 什么是 PGO?
答案:Profile-Guided Optimization。将生产环境的 CPU Profile 反馈给编译器,编译器据此优化热路径(如函数内联、分支预测)。Go 1.21 开始支持,放一个 default.pgo 文件在项目根目录即可。