参考:
https://www.flysnow.org/2017/05/12/go-in-action-go-context.html
1、Context接口
Context的接口定义的比较简洁,我们看下这个接口的方法。
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
这个接口共有4个方法,了解这些方法的意思非常重要,这样我们才可以更好的使用他们。
1.1、Deadline方法
是获取设置的截止时间的意思,
-
第一个返回式是
截止时间,到了这个时间点,Context会自动发起取消请求; -
第二个返回值ok==false时表示
没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。
1.2、Done方法
返回一个只读的chan,类型为struct{},
-
我们在goroutine中,如果该方法返回的chan可以
读取(也就是阻塞状态结束),则意味着parent context已经发起了取消请求, -
我们通过Done方法收到这个
信号后,就应该做清理操作,然后退出goroutine,释放资源。
1.3、Err方法
返回取消的错误原因,因为什么Context被取消。
1.4、Value方法
获取该Context上绑定的值,是一个键值对,所以要通过一个Key才可以获取对应的值,这个值一般是线程安全的。
以上四个方法中常用的就是Done了,如果Context取消的时候,我们就可以得到一个关闭的chan,关闭的chan是可以读取的,所以只要可以读取的时候,就意味着收到Context取消的信号了,以下是这个方法的经典用法。
func Stream(ctx context.Context, out chan<- Value) error {
for {
v, err := DoSomething(ctx)
if err != nil {
return err
}
select {
case <-ctx.Done():
return ctx.Err()
case out <- v:
}
}
}
2、Context接口分析
并不需要我们实现,Go内置已经帮我们实现了2个,我们代码中最开始都是以这两个内置的作为最顶层的partent context,衍生出更多的子Context。
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}
2.1、Background
一个是Background,主要用于main函数、初始化以及测试代码中,作为Context这个树结构的最顶层的Context,也就是根Context。
2.2、TODO
一个是TODO,它目前还不知道具体的使用场景,如果我们不知道该使用什么Context的时候,可以使用这个。
2.3、emptyCtx结构体类型
他们两个本质上都是emptyCtx结构体类型,是一个不可取消,没有设置截止时间,没有携带任何值的Context。
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
}
这就是emptyCtx实现Context接口的方法,可以看到,这些方法什么都没做,返回的都是nil或者零值。












网友评论