开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
是什么
定义:context可以理解为goroutine的上下文信息,功能包括有:取消信号,超时时间,截止时间,传递kv等
常见用途:
- 超时控制,并发控制,存储键值,并发安全控制(如果命令执行失败,同时停止所有正在并发的所有goroutine
- context用于解决goroutine之间退出通知、元数据传递的功能的问题
创建context:
ctx := context.Background() //ctx是一个空的context,它不能被取消,没有值,也没有超时时间
//四个子节点创建函数:WithCancel、WithTimeout、WithDeadline、WithValue
//func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
//func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
//func WithValue(parent Context, key, val interface{}) Context
//func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
使用建议:
- 建议命名ctx,不要将其塞进结构体中,直接作为函数的第一参数
- 不要传nil的context,可以使用准备好的context:todo
- 存储共同需要的上下文数据
- context是并发安全的
如何使用
-
传递共享数据,使用
ctx.Value() -
设置定时取消
- 出现场景:网络延迟,机器负载过高的场景下,数据获取的时间过长,为了避免请求堵塞甚至是雪崩
-
同时停止多个goroutine:
- 出现场景:goroutine运行的过程中出错了,或者需要通途退出,需要context去关闭该goroutine,防止泄漏
底层原理
接口
Context定义了四个接口,这四个接口都是幂等的
-
Deadline() (deadline time.Time, ok bool) -
Done() <-chan struct{},返回一个只读channel,直接读改channel被被阻塞住,等待完成。完成之后会读出0值进行后续判断 -
Err() error -
Value(key interface{}) interface{}- 查找的方向时向上的,父节点没有办法获取子节点存储的值,子节点却可以获取父节点的值
Canceler
*cancleCtx,*timerCtx实现了Canceler接口
-
cancel(removeFromParent bool, err error)-
cancle函数的功能就是关闭c.done,递归的取消所有的子节点,从父节点中删除自己。达到的效果是通过关闭channel,将取消信号传递给了它的所有子节点
- 当removeFromParent为true的时候,会将当前节点的context从父节点context删除。新创建一个可以取消的context节点时,返回的cancelFunc函数里面会传入true;删除父节点的时候,就没必要传true
-
-
Done() <-chan struct{}
其他
实际项目中,会自己构造一些上下文信息,用来存储不同的状态信息。比如说在数据库的状态并发控制的时候,会记录不同操作的修改范围进行比较。