在 Go 语言中,context
包(package context
)是用于跨 goroutine 传递请求作用域数据、控制并发生命周期的核心工具。它主要用于解决以下问题:
1. 核心作用
功能 | 说明 |
---|---|
取消传播 | 通过 ctx.Done() 通知多个 goroutine 退出(如超时、手动取消)。 |
超时控制 | 通过 WithTimeout /WithDeadline 设置截止时间,自动触发取消。 |
值传递 | 通过 WithValue 安全传递请求范围内的数据(如 traceID、认证信息)。 |
父子级联取消 | 父 context 被取消时,所有派生出的子 context 会自动触发取消。 |
2. Context 接口方法
type Context interface {
Deadline() (deadline time.Time, ok bool) //返回设置的截止时间
Done() <-chan struct{} //返回一个 channel,用于监听取消信号
Err() error //返回取消原因(超时/主动取消)
Value(key any) any //获取关联的值
}
3. 常用创建函数
(1) Background / TODO
ctx := context.Background() //根 context,通常作为顶层 context
ctx = context.TODO() //暂不确定用途时的占位符(语义化)
(2) WithCancel
ctx, cancel := context.WithCancel(parentCtx)
defer cancel() //手动调用 cancel() 触发取消
(3) WithTimeout / WithDeadline
// timeout: "从现在开始最多允许运行多久"
ctx, cancel := context.WithTimeout(parentCtx, time.Second * 5)
defer cancel()
// deadline: "必须在某个具体时间点前完成"
deadline := time.Now().Add(time.Second * 5)
ctx, cancel := context.WithDeadline(parentCtx, deadline)
(4) WithValue
type key string
ctx := context.WithValue(parentCtx, key("userID"), "123")
userID := ctx.Value(key("userID")).(string) //需类型断言
⚠️ 注意:
- Key应使用自定义类型(避免字符串冲突)。
- Value应该是线程安全的不可变数据。
4. 典型应用场景
(1) HTTP Server 请求控制
func handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
select {
case <-time.After(2 * time.Second):
fmt.Fprint(w, "Hello")
case <-ctx.Done(): //客户端断开连接时触发
err := ctx.Err()
log.Printf("Request canceled: %v", err)
}
}
(2) RPC/数据库查询超时
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
result, err := db.QueryContext(ctx, "SELECT...")
if errors.Is(err, context.DeadlineExceeded) {
log.Println("Query timeout!")
}
(3) Goroutine 树的生命周期管理
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return //父级取消时自动退出
default:
fmt.Println("Working...")
time.Sleep(time.Second)
}
}
}
func main() {
parentCtx, cancel := context.WithCancel(context.Background())
go worker(parentCtx)
time.Sleep(5 * time.Second)
cancel() //通知所有子 goroutine退出
}
5. ⚠️注意事项
- 不要滥用 WithValue:仅传递必要的请求范围数据(如 traceID),而非函数参数。
- 及时释放资源:调用
cancel()
防止 goroutine泄漏(即使提前结束)。 - Err()检查必要性:
if ctx.Err() == context.Canceled { ... }
- 性能影响:频繁创建嵌套的context可能增加微小开销。
6. vs Channel + Select
Context | Channel + Select | |
---|---|---|
适用场景 | 树状goroutine生命周期管理 | 简单的一对一通信 |
灵活性 | 内置超时/值传递 | 需手动实现 |
标准库支持 | 广泛集成于HTTP/gRPC/database等 | 原生语法 |
总结:
Context是Go并发编程中管理复杂任务链路的首选工具,尤其在微服务、网络请求等场景下不可或缺。
内容由零声教学AI助手提供,问题来源于学员提问