context 通过树形结构传播取消:WithCancel/WithTimeout/WithDeadline 基于父 ctx 派生子 ctx,父节点取消时会级联关闭所有后代的 Done() channel。下游 goroutine 用 select 监听 ctx.Done() 感知取消并退出,形成从请求入口到底层调用的传播链。ctx 不可变、值语义,沿调用链显式传递,约定作为函数第一个参数,不存进结构体(http.Request 这类框架层例外)。
ctx, cancel := context.WithTimeout(parent, 2*time.Second)
defer cancel() // 必须调用,否则 timer 资源泄漏
select {
case res := <-do(ctx):
return res
case <-ctx.Done():
return ctx.Err() // Canceled 或 DeadlineExceeded
}
关键点:cancel 必须调用(go vet 有 lostcancel 检查);context 只负责发信号,被调方必须主动检查 Done 才能真正停止,卡在不可中断调用里取消无效。WithValue 只放请求级元数据(trace id、认证信息),不拿来传业务参数。
Go 1.21 起 WithCancelCause/WithoutCancel 补充了取消原因传递与断链场景。追问方向:ctx 在 database/sql、http server 中的集成、取消时的资源清理顺序。