Skip to main content

Go: 标准库 context

📅 2026-03-13 ✏️ 2026-03-23 Go 标准库 CS GO

1 · 标准库 context#

https://go.dev/blog/context

context 包定义了一个上下文Context类型;

这个类型在跨越 API 边界和进程之间,携带了超时,取消信号,以及其他请求域内的值;

在不同执行任务(比如 goroutine)之间传递Context值,可以实现超时,取消功能,也可以实现跨越函数的参数传递;

context 是接受信号的一方,是子操作;

派生树模型,在父ctx上派生出子ctx;

本质:一条调用链/传播链上各个节点共享一套:是否超时、是否取消、值的机制。

1.1 · Context 接口#

type Context interface {
	// 返回截止时间,ok 为 false 表示没有设置 deadline
	// ! 未来什么时候结束,还未结束
	Deadline() (deadline time.Time, ok bool)

	// 返回一个 channel,当 context 被取消或超时时关闭;永远不会取消的 context 返回 nil
	// ! 已经结束
	Done() <-chan struct{}
	// Done 未关闭返回 nil;已关闭返回原因(Canceled 或 DeadlineExceeded)
	Err() error

	// 返回 key 关联的值,不存在返回 nil
	Value(key any) any
}

1.2 · 根 Context#

  • context.Background() — 通常用于 main、init 或顶层请求入口
  • context.TODO() — 不确定用哪个 Context 时的占位符

1.3 · 派生函数

1.3.1 · 基础派生函数

函数作用
WithCancel(parent)返回可手动取消的子 context 和 cancel 函数
WithDeadline(parent, d)到达时间点 d 自动取消
WithTimeout(parent, t)经过时长 t 自动取消(等价于 WithDeadline(parent, time.Now().Add(t))
WithValue(parent, key, val)附带一个 key-value 对,用于请求域数据的传递

WithoutCancel(parent) 返回一个不会随父 context 取消而取消的派生 context AfterFunc(ctx, f) ctx 取消后,在新 goroutine 中执行 f(Go 1.21)

1.3.2 · 带 Cause 的取消 API#

函数作用
WithCancelCause(parent)在普通取消基础上额外记录一个自定义 error 原因(Go 1.20+)
WithDeadlineCause(parent, d, cause)在 deadline 取消基础上额外记录一个自定义 error 原因
WithTimeoutCause(parent, t, cause)在 timeout 取消基础上额外记录一个自定义 error 原因
Cause(ctx)读取 context 被取消的具体原因;若未显式指定 cause,则返回值通常与 ctx.Err() 一致

当一个 Context 被取消时,所有从它派生的子 Context 也会被取消。

1.4 · 使用规则

  1. 不要把 Context 存在 struct 里显式作为函数第一个参数传递,通常命名 ctx
  2. 不要传 nil Context,不确定时用 context.TODO()
  3. Value 只用于请求域数据(如 trace ID、认证信息),不要用来传可选参数
  4. Context 是并发安全的,多个 goroutine 可同时使用
  5. cancel 函数调用后要尽快执行(通常 defer cancel()),避免资源泄漏

1.5 · 错误值

调用 Err() 返回

  • context.Canceled — 手动调用 cancel 函数时
  • context.DeadlineExceeded — deadline/timeout 到期时

1.6 · Go 中 context.Value 应该放什么#

如果你的代码“没有这个值就无法运行”,那这个值就不应该放进 context。 context 是“附带信息的通道”,不是“参数传递的替代品”

1.7 · cancellation cause#

谁先 cancel,谁定义原因cause

NOTE: 为什么 WithTimeoutCause 不返回 CancelCauseFunc:手动 cancel → 原因变成 context.Canceled