共计 2313 个字符,预计需要花费 6 分钟才能阅读完成。
摘要
在很多的 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()
示意如果有截止工夫的话,得返回对应 deadline 工夫;如果没有,则 ok 的值为 false。
Done()
示意对于 channel 的数据通信,而且它的数据类型是 struct{},一个空构造体,因而在 Go 里都是间接通过 close channel 来进行告诉的,不会波及具体数据传输。
Err()
返回的是一个谬误 error,如果下面的 Done() 的 channel 没被 close,则 error 为 nil;如果 channel 已被 close,则 error 将会返回 close 的起因,比方超时或手动勾销。
Value()
则是用来存储具体数据的办法。
Context 类型
简略的看过 Context 接口之后,咱们来看看官网的 context 类型。次要有四种,别离是 emptyCtx
,cancelCtx
,timerCtx
,valueCtx
:
- emptyCtx:空的 context,实现了下面的 4 个接口,但都是间接 return 默认值,没有具体性能代码。
- cancelCtx:用来勾销告诉用的 context
- timerCtx:用来超时告诉用的 context
- valueCtx:用来传值的 context
其中:
emptyCtx 示意什么都没有的 context,个别用作最初始的 context,作为 父 context 应用。像咱们常见的 context.Background()
返回的就是 emptyCtx。
其余类型的创立办法如下:
- WithCancel 办法创立的是 cancelCtx 类型的 context。
- WithDeadline 办法创立的是 timerCtx 类型的 context。
- WithValue 办法创立的是 valueCtx 类型的 context。
下面三个办法在创立的时候都会要求传 parent context 进来,以此达到 链式传递 信息的目标。
Context 源码
context 的源码在 src/context/context.go 里,置信大家认真钻研,也能看到下面介绍的几个 context 对象。这边简略解释下 cancelCtx
、timerCtx
、valueCtx
的外围流程。
1)cancelCtx、timerCtx(用来告诉用的 context)
cancelCtx、timerCtx 在创立的时候都会调用 propagateCancel
办法,将以后的 context 挂在 父 context 下。
接着在 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 都会触发勾销。
感兴趣的敌人能够搜一搜公众号「阅新技术」,关注更多的推送文章。
能够的话,就顺便点个赞、留个言、分享下,感激各位反对!
阅新技术,浏览更多的新常识。