trace.start() 必须显式调用且配对 trace.stop(),否则 trace.out 为空或仅有头尾事件;常见原因包括未传 *os.file、stop 未执行、程序过快退出、start 放置过晚。

trace.Start() 必须显式调用且配对 trace.Stop(),否则 trace.out 是空的或只有头尾两个事件——所有“打不开”“no trace events”的问题,90% 都卡在这一步。
为什么 go tool trace 打开后显示 “no trace events”
不是浏览器问题,也不是命令写错,而是 trace 文件本身没写入有效事件。常见原因有:
-
trace.Start()没传*os.File,比如只写了trace.Start(os.Stdout)或干脆漏掉参数——它默认写内存缓冲区,不落盘 -
trace.Stop()没执行,比如用了os.Exit(1)或log.Fatal()提前退出,它们跳过defer - 程序运行太快,
trace.Start()后没触发任何 goroutine 调度、系统调用或 GC,比如只做初始化就退出;加time.Sleep(200 * time.Millisecond)强制留出采集窗口 -
trace.Start()放得太晚,例如在http.ListenAndServe()之后——handler 里的所有调度事件全丢
验证是否有效:运行 file trace.out,输出应为 Go execution trace;文件大小应 >1KB。
如何让 Scheduler Latency 面板真正出现
这个面板是定位调度延迟的核心,但它默认不激活。必须同时满足三个条件:
- 启动时设置环境变量:
GODEBUG=scheddetail=1,schedtrace=1000 - 在
trace.Start()前调用runtime.SetBlockProfileRate(1)(值非零即可,这是隐藏触发开关) - 确保程序中真有阻塞行为(如 channel 等待、锁竞争、syscall),否则 runtime 不会生成 sched 事件
缺任一条件,UI 只显示模糊的 “Proc Status”,不会出现 “Scheduler Latency” 标签页。注意:Go 1.21+ 中 scheddetail 仍有效,但字段含义有调整,别照搬老文档解读。
goroutine 处于 Runnable 却长时间不 Running,怎么查
灰色竖条就是调度延迟本身,重点看 Goroutines 视图里每个 G 的 Runnable 区段长度:
- 如果多个 G 同时卡在 Runnable,且持续 >1ms,先看 Scheduler latency 面板里各 P 的延迟分布——某 P 持续高延迟,可能是锁竞争或 GC STW 影响
- 如果所有 P 的 runq 长度都接近 0,但 G 还是不 Running,说明问题不在队列排队,而在 P 被抢占或 M 卡住(比如 cgo 调用未释放 P)
- 切换到 Network blocking 或 Synchronization blocking 子视图,确认是否集中在某个 fd、mutex 或 channel 上
- 别只盯着 “Running” 状态——长时间 Running 很可能只是在等系统调用返回,不是 CPU 密集
trace 数据本身会影响调度器行为,高频 goroutine 创建/销毁场景下,采样开销不可忽略。生产环境慎用全量 trace,压测可用,但别直接拿 trace 下的 P99 延迟对标非 trace 场景。
容器或 CI 里生成的 trace 文件打不开
核心是时间戳精度和内核支持差异。Linux 容器若使用低版本内核(CLOCK_MONOTONIC_RAW 不可用),trace 时间线会错乱甚至解析失败。Mac 上 Safari 因安全策略常拒载本地 trace 数据,换 Chrome 或 Firefox。
另外注意 Go 版本兼容性:go tool trace 工具和 trace 文件必须版本匹配。1.21+ 生成的文件不能用 1.20 的工具解析。还有个容易被忽略的点:trace.Start() 后长期不 trace.Stop(),buffer(固定 64MB)会循环覆盖,早期关键事件丢失——线上服务务必通过信号(如 SIGUSR2)控制启停,而不是无条件开启。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











