Go的runtime/trace不用于查函数耗时,仅记录goroutine调度、GC、系统调用等运行时事件;trace.out为空或过小主因是trace.Stop()未执行、程序过快退出或缺乏调度/I/O/GC等触发事件。

Go 的 runtime/trace 不是用来查函数耗时的,它只记录运行时事件——goroutine 调度、GC、系统调用、网络/同步阻塞等。想定位 HTTP handler 执行慢?该用 pprof;想看哪段代码占 CPU?别指望 trace 出火焰图。
trace.Start() 后 trace.out 为空或只有几十字节
这是最常见问题,本质是 trace 数据根本没写入磁盘或只写了头尾。
-
trace.Stop()没执行:比如os.Exit(0)、panic()或log.Fatal()会跳过defer,导致文件截断,go tool trace报EOF或unknown magic number - 程序运行时间太短:
trace.Start()默认约 10ms 采样一次,纯计算、无 goroutine 切换、无 I/O、无 GC 的代码几乎不产生事件;time.Sleep(20 * time.Millisecond)很可能只录到ProcStart和GCStart - 误传
os.Stdout或日志 writer:混入其他文本会导致二进制格式损坏,go tool trace直接拒绝解析 - 在
init()里调trace.Start():此时 runtime 尚未初始化,静默失败(你甚至收不到错误)
生成可被 go tool trace 解析的 trace.out 文件
可靠写法就三件事:开文件、传给 trace.Start()、确保 trace.Stop() 执行。
- 必须用
os.Create("trace.out")创建*os.File,不能传路径字符串或io.Writer包装器 -
trace.Stop()内部已调f.Close(),所以defer f.Close()不是必须的,但留着也不冲突 - 必须留出采集窗口:至少
time.Sleep(100 * time.Millisecond),推荐 200–500ms;若逻辑本身耗时长,可省略 sleep,但要确保有调度/GC/I/O 触发点 - 避免在
main()开头就defer trace.Stop():若main()返回前 runtime 还没 flush 完,文件仍可能不完整
go tool trace 打不开或显示 “No traces found”
90% 是 trace 文件本身无效,和浏览器无关。
立即学习“go语言免费学习笔记(深入)”;
- 先验证文件:运行
file trace.out,输出必须是Go execution trace;大小应 >1KB;空文件或几百字节说明trace.Stop()没执行 - 绝对不要双击打开
.out文件,也不要直接用file://协议访问——Chrome/Safari 会报 CORS error;正确方式是go tool trace -http=:8080 trace.out,再手动访问http://localhost:8080 - Mac 上 Safari 可能因安全策略拒绝加载,换 Chrome 或 Firefox
- 如果提示
failed to read trace: unrecognized trace version,基本是文件被截断或误用了 pprof 输出当 trace
为什么看不到 Scheduler latency 面板或函数级耗时
因为这些压根不是 runtime/trace 的能力范围。
-
Scheduler latency面板默认不激活,需同时满足三个条件才会出现:有足够多的 goroutine 调度事件、程序运行时间够长、且 trace 文件未被截断——它不是开关,是数据驱动的 -
View trace页面只展示 goroutine 状态变迁(running/blocking/gc)、OS 线程、P、堆分配等底层视图,没有调用栈、没有函数名、没有 CPU 时间聚合 - 想看函数耗时,必须用
net/http/pprof或runtime/pprof;想串联跨服务链路,得用 OpenTelemetry,runtime/trace不参与 context 传播,也不生成 trace-id
真正容易被忽略的是:trace 不是“开了就自动有数据”,它极度依赖程序是否实际触发了运行时事件。一个没 channel、没 time.Sleep、没 http.Get、没 GC 的纯 for 循环,哪怕跑 5 秒,trace 里也可能只有 ProcStart 和几个 timestamp 事件。


















