注:每天进步一点点,记录每日成长,思考的第07/365天 ;
本文预计阅读时间: 3分钟
1
01
context是什么
通过context,我们可以方便地对同一个请求所产生地goroutine进行约束管理,可以设定超时、deadline,甚至是取消这个请求相关的所有goroutine。
context包的核心
type Context interface {
//如果存在,返回当前Context任务被取消的截止时间;
Deadline() (deadline time.Time, ok bool)
//当Context被canceled或是times out的时候,Done返回一个被closed的channel;否则返回nil
//【用来传递结束信号以抢占并中断当前任务】
Done() <-chan struct{}
//如果Done返回的channel没有关闭,将返回nil;
//如果Done返回的channel已经关闭,将返回非空的值表示任务结束的原因。
//如果是context被取消,Err将返回Canceled;
//如果是context超时,Err将返回DeadlineExceeded。
Err() error
//如果存在,Value返回与key相关了的值,不存在返回 nil
Value(key interface{}) interface{}
}复制
1
02
emptyCtx类型
emptyCtx
是一个int
类型的变量,它实现了context
的接口。emptyCtx
没有超时时间,不能取消,也不能存储任何额外信息,所以emptyCtx
用来作为context
树的根节点。
// emptyCtx不能被取消,没有值,也没有deadline
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"
}
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}复制
有两种方法创建根 Context,一个是 Background(),一个是 TODO(),这两个函数都会返回一个空 Context 的实例。根 context 不会被 cancel。这两个方法只能用在最外层代码中,比如 main 函数里。一般使用 Background() 方法创建根 context。TODO() 用于当前不确定使用何种 context。
1
03
派生Context
一个Context被cannel,那么它的派生context 都会收到取消信号。有四种方法派生 context :
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context复制
WithCancel 对应的是 cancelCtx ,其中,返回一个 cancelCtx ,同时返回一个 CancelFunc,CancelFunc 是 context 包中定义的一个函数类型:type CancelFunc func()。调用这个 CancelFunc 时,关闭对应的c.done,也就是让他的后代goroutine退出。
WithDeadline 和 WithTimeout 对应的是 timerCtx ,WithDeadline 和 WithTimeout 是相似的,WithDeadline 是设置具体的 deadline 时间,到达 deadline 的时候,后代 goroutine 退出,而 WithTimeout 简单粗暴,直接 return WithDeadline(parent, time.Now().Add(timeout))。
WithValue 对应 valueCtx ,WithValue 是在 Context 中设置一个 map,拿到这个 Context 以及它的后代的 goroutine 都可以拿到 map 里的值。
1
04
Context使用规则
a)勿将Context作为struct的字段使用,而是对每个使用其的函数分别作参数使用,其需定义为函数或方法的第一个参数,一般叫作ctx;
b)勿对Context参数传nil,未想好的使用那个Context,请传context.TODO
;
c)使用context传值仅可用作请求域的数据,其它类型数据请不要滥用;
d)同一个Context可以传给使用其的多个goroutine,且Context可被多个goroutine同时安全访问。
1
05
总结
context
主要用于父子任务之间的同步取消信号,本质上是一种协程调度的方式。