Go官方不提供Goroutine ID,推荐用context携带UUID、sync.Map缓存标识或闭包变量地址区分协程;监控泄漏应结合runtime.Stack采样、pprof分析与GC统计,避免误判NumGoroutine瞬时值。
获取当前 Goroutine ID 的替代方案
Go 官方明确不提供 runtime.GoroutineID(),因为 Goroutine 没有稳定、可导出的 ID;所谓“ID”只是调度器内部调试用的临时编号,且可能复用或不可见。强行通过反射或汇编提取会破坏兼容性,Go 1.22+ 已让这类 hack 更难生效。
实际需要区分协程时,推荐以下方式:
- 用
sync.Map+unsafe.Pointer(或uintptr)缓存自定义上下文标识,例如在入口处生成唯一uuid并存入context.Context - 对调试场景,启用
GODEBUG=gctrace=1或使用runtime.ReadMemStats()配合pprof观察 goroutine 堆栈快照 - 若仅需“当前协程是否相同”,可用
func() {}闭包捕获的变量地址作轻量标记(注意逃逸)
监控 Goroutine 数量变化的可靠方法
runtime.NumGoroutine() 返回的是当前**可运行 + 运行中 + 等待中**的 goroutine 总数,但它是个瞬时快照,无法直接反映泄漏。常见误判是看到数字持续上涨就断定泄漏,而忽略了 GC 周期和阻塞系统调用的影响。
更稳妥的做法是: