在很多的 Go 开源框架里,我们经常能看到 context 的身影,它的使用场景有很多,像超时通知,取消通知都用到了 context。今天我们就来好好的认识一下它,看看 context 的相关知识和底层原理。
context 介绍context 从它的字面量就可以看出来,是用来传递信息的。当然,这种传递并不仅仅是将数据塞给被调用者,它还能进行链式的传递,通过保存父子 context 关系,不断的迭代遍历来获取数据。
除此之外,context 还能进行链式的传播 channel 信号。
我们知道 channel 是用来做 goroutine 通信使用的。这就使得 goroutine 之间能够进行链式的信号通知了,进而达到自上而下的通知效果。
例如通知所有跟 context 有血缘关系的 goroutine 进行取消动作。
Context 接口在 Go 里并没有直接为我们提供一个统一的 context 对象,而是设计了一个接口类型的 Context。然后在这些接口上来实现了几种具体类型的 context。
这样的好处就是我们只要根据开放出来的接口定义,也能够实现属于自己的 context,进而跟官方的 context 一起配合使用。
在分析官方的几种 context 之前,我们先来看看 context 要求实现的几个接口:
- Deadline() (deadline time.Time, ok bool)
- Done() <-chan struct{}
- Err() error
- Value(key interface{}) interface{}
其中:
Deadline()
Done()
Err()
Value()
Context 类型
emptyCtxcancelCtxtimerCtxvalueCtx
- emptyCtx:空的 context,实现了上面的 4 个接口,但都是直接 return 默认值,没有具体功能代码。
- cancelCtx:用来取消通知用的 context
- timerCtx:用来超时通知用的 context
- valueCtx:用来传值的 context
context.Background()
其他类型的创建方法如下:
- WithCancel 方法创建的是 cancelCtx 类型的 context。
- WithDeadline 方法创建的是 timerCtx 类型的 context。
- WithValue 方法创建的是 valueCtx 类型的 context。
上面三个方法在创建的时候都会要求传 parent context 进来,以此达到链式传递信息的目的。
Context 源码cancelCtxtimerCtxvalueCtx
1)cancelCtx 、timerCtx(用来通知用的 context)
propagateCancel
接着在 Done() 方法里返回了对应的 channel,让调用者能够监听 channel 信号。
当要执行取消动作时,会通过 cancel 方法关闭 channel,来达到通知 goroutine 的目的。
在 channel 关闭的同时也会对子 context 调用 cancel 方法,直到没有子 context。
cancelCtx 和 timerCtxt 不同之处就在于 cancelCtx 是手动调用 cancel 方法来触发取消通知;
而 timerCtxt 则通过 AfterFunc 超时时间来自动触发 cancel 方法。
2)valueCtx(用来传值的 context)
valueCtx 通过 key-value 形式来存储数据,当找不到 key 时,就会到 父 context 里查找,直到没有父 context:
func (c *valueCtx) Value(key interface{}) interface{} {
if c.key == key {
return c.val
}
return c.Context.Value(key) // 到父 context 里查找
}
context 注意事项
最后我们来看看在使用 context 时的几个注意事项:
- context 的 Done() 方法往往需要配合 select {} 使用,以监听退出。
- 尽量通过函数参数来暴露 context,不要在自定义结构体里包含它。
- WithValue 类型的 context 应该尽量存储一些全局的 data,而不要存储一些可有可无的局部 data。
- context 是并发安全的。
- 一旦 context 执行取消动作,所有派生的 context 都会触发取消。
感兴趣的朋友可以搜一搜公众号「 阅新技术 」,关注更多的推送文章。
可以的话,就顺便点个赞、留个言、分享下,感谢各位支持!
阅新技术,阅读更多的新知识。