context用于取消传播、超时控制和跨层传值;withcancel主动中断goroutine,需defer cancel()防泄漏;withtimeout防i/o卡死;withvalue传只读元数据;background为根上下文,todo仅作临时占位。

Context 不是用来“学习”的,而是用来解决具体问题的:取消传播、超时控制、跨层传值。直接上手用,比先学理论更有效。
用 WithCancel 主动中断 goroutine
当你需要在运行中手动终止下游操作(比如用户点击取消按钮、服务主动下线某任务),WithCancel 是最直接的选择。它返回一个 ctx 和一个 cancel 函数,调用后者即触发所有监听 ctx.Done() 的 goroutine 退出。
- 必须
defer cancel(),否则可能泄漏内存(子 context 仍挂在父节点的childrenmap 中) -
cancel()可安全重复调用,多次调用不会 panic,但只有第一次生效 - 不要把
cancel函数传给不可信代码——它一旦被误调,整条调用链就断了
用 WithTimeout 防止网络请求卡死
HTTP 客户端、数据库查询、RPC 调用等 I/O 操作,必须设上限时间。WithTimeout 是最常用方式,它本质是 WithDeadline 的封装,基于当前时间 + 持续时间计算截止点。
- 超时后
ctx.Err()返回context.DeadlineExceeded,不是nil - 注意单位:传
5 * time.Second,别写成5000(毫秒)——Go 不做隐式转换 - 如果上游已带超时,再套一层
WithTimeout可能导致提前取消,优先复用已有 ctx
用 WithValue 传请求级元数据
比如 trace ID、用户身份、请求开始时间。它不用于业务逻辑参数传递,只承载“上下文相关、非核心逻辑”的只读数据。
- key 必须是自定义类型(如
type requestIDKey struct{}),不能用string或int——避免不同包之间 key 冲突 - value 应为不可变或只读结构;若传指针,需确保生命周期不早于 ctx
- 频繁调用
Value有轻微性能开销(需遍历链表),高频路径慎用
为什么 Background 和 TODO 不能互换
context.Background() 是根 context,服务器启动、main 函数初始化时唯一合法起点;context.TODO() 是占位符,仅用于你还没想好该用哪个 context 的临时场景(比如函数签名未定、第三方库未适配)。
- 在 HTTP handler 中硬编码
TODO,等于放弃超时和取消能力,生产环境会出问题 - 测试中用
TODO可以,但上线前必须替换成带超时或取消的 context - 静态检查工具(如
staticcheck)会警告未使用的TODO,这是个信号:该补 context 了
真正难的不是记住五个函数,而是在每一层函数签名里坚持加 ctx context.Context 参数,并在每处阻塞调用(time.Sleep、http.Do、db.Query)前检查 ctx.Done() ——漏掉一次,整条链就失去控制力。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











