1. 理解context的本质
在Go语言中,context包就像是一个精密的交通信号系统。想象一下,你正在指挥一个繁忙的十字路口,有数十辆汽车(goroutine)同时通过。如果没有红绿灯(context),这些车辆可能会无休止地运行,造成交通堵塞(资源泄漏)。context就是为这些并发任务提供统一控制机制的核心组件。
context.Context接口定义了四个关键方法:
go复制type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
这些方法共同构成了context的核心能力:
- Deadline():获取任务的截止时间,用于超时控制
- Done():返回一个通道,用于接收取消信号
- Err():获取context结束的原因
- Value():在调用链中安全传递请求范围的数据
提示:context的设计遵循了显式传递原则,应该作为函数的第一个参数明确传递,而不是隐藏在结构体或全局变量中。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. context的创建与派生
2.1 根context的创建
所有context都源自两个根context:
go复制ctx := context.Background() // 空context,通常用于main函数或测试
ctx = context.TODO() // 临时占位,后续应该替换为具体context
实际项目中,Background()是最常用的根context,它就像一个空白画布,我们可以基于它派生出具有具体功能的context。
2.2 派生context的四种方式
2.2.1 WithCancel:手动取消控制
go复制ctx, cancel := context.WithCancel(parentCtx)
go func() {
<-ctx.Done() // 阻塞等待取消信号
fmt.Println("任务被取消")
}()
// 当需要取消时
cancel()
