go-Context包详解
在go语言中,上下文context.Context用来设置截止日期、同步信号、传递请求相关值得结构体。上下文与Goroutine得关系比较密切,是go语言中独特得设计,在其他编程语言中很少见到类似的概念。
context.Context是一个接口,定义了如下四个方法:
// A Context carries a deadline, a cancellation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
// 返回被取消的时间,即完成工作的截止日期
Deadline() (deadline time.Time, ok bool)
// Done返回一个channal,这个channel会在当前工作完成或上下文被取消后关闭,多次调用会返回同一个channel
Done() <-chan struct{}
// 返回结束的原因,只会在Done方法对应的Channel关闭时返回非空值
// 如果被取消,返回Canceld错误;如果超时,返回DeadlineExceeded错误
Err() error
// 从context.Context中获取键对应的值
Value(key interface{}) interface{}
}
设计原理
context.Context的最大作用,在goroutine构成的树形结构中同步信号以减少计算资源的浪费。
当最上层的Goroutine因为某些原因执行失败时,下层的goroutine如果没有接受到这个信号会继续工作;但是当正确使用context时,就可以在下层及时停掉无用的工作以减少额外的资源消耗。
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1 * time.Second)
defer cancel()
go handle(ctx, 5 * time.Second)
select {
case <-ctx.Done():
fmt.Println("in main", ctx.Err())
}
}
func handle(ctx context.Context, duration time.Duration) {
select {
case <-ctx.Done():
fmt.Println("in handle", ctx.Err())
case <-time.After(duration):
fmt.Printf("after %v seconds\n", duration)
}
}
这个例子简单理解context的使用方法和设计原理–```多个goroutine同时订阅ctc.Done()这个channel的消息,一旦接收到取消信号就立刻停止当前正在执行的工作。
默认上下文
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}
默认上下文永远不会取消,也没有value,没有deadline。
取消信号
context.WithCancel能够从context.Context中衍生出新的子上下文,并返回用于取消该上下文的函数。
// WithCancel返回parent的拷贝,但是包含新Done channel,同时返回一个取消函数
// 当取消函数执行,或者parent的Done channel关闭,这个新的Done channel都会关闭
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
if parent == nil {
panic("cannot create context from nil parent")
}
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
}
- newCancelCtx将传入的上下文封装成私有结构体cancelCtx
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具