Go 中启用 CPU Profiling 需调用 pprof.StartCPUProfile 启动并确保在进程退出前用 StopCPUProfile 停止;推荐 defer + 信号监听,HTTP 服务可借 /debug/pprof/profile 按需采集;分析时必须使用原始可执行文件,注意 off-CPU 场景无法捕获。
Go 自带的 pprof 包支持开箱即用的 CPU 采样,不需要额外依赖。关键在于:必须调用 pprof.StartCPUProfile 启动,并在退出前调用 pprof.StopCPUProfile —— 否则不会生成任何数据。
/tmp/cpu.pprof),且路径存在main() 返回后才调用 StopCPUProfile,否则进程已退出,写入失败defer 配合信号监听(如 os.Interrupt)来保证优雅停止runtime.SetCPUProfileRate(500) 提高精度(注意:过高会增加性能开销)对长期运行的服务(如 Web 服务),更常用的是通过内置 HTTP 接口按需采集,避免修改源码。前提是已导入并注册了 net/http/pprof。
import _ "net/http/pprof",且该路由已注册(通常只要 mux 路由包含 /debug/pprof/ 即可)wget -O cpu.pprof "http://localhost:8080/debug/pprof/profile?seconds=30",其中 seconds=30 表示持续采样 30 秒404,检查是否漏掉 import _ "net/http/pprof",或端口/路径是否被防火墙或反向代理拦截拿到 cpu.pprof 文件后,用 go tool pprof 分析。但很多用户卡在「打开后全是空白」或「显示 no samples」——本质是符号未解析或二进制不匹配。
./myserver 采集的 profile,就得用同一份 ./myserver(非重新编译过的)来分析go tool pprof cpu.pprof → 缺少二进制,无法解析函数名;正确写法:go tool pprof ./myserver cpu.pprof
top;火焰图生成:go tool pprof -http=:8081 ./myserver cpu.pprof(需安装 graphviz)runtime.mcall 或 runtime.futex 占比高,往往说明协程阻塞严重(如锁竞争、channel 等待),不是 CPU 密集型问题go tool pprof -http=:8081 ./myserver cpu.pprof
CPU profiling 只能捕获正在运行(on-CPU)的 goroutine 栈,对 I/O 等待、channel 阻塞、GC 暂停等 off-CPU 场景完全无感知。它告诉你“CPU 花在哪”,但不
回答“为什么卡住”。
runtime.gopark —— 这时该换用 goroutine 或 trace profileruntime.LockOSThread() 并开启 GODEBUG=cgocheck=0,但不推荐)???