go语言context包源码解析
由于需要转go,学了基础和一些服务端框架后决定对go的一些源码进行阅读,并适当去实现。第一份源码就看了context,下面对context进行详细的解读。
源码部分请详细阅读注释,写得很清楚。注意:源码是我自己看了context官方包造的轮子,基本没太大的差别,注释中写了一些我遇到的问题的详细解释(比如实现过程中go中的锁不可重入带来的问题),代码可以在GitHub中下载,地址,用goland打开阅读体验更佳强烈建议仔细阅读源码阅读顺序不一定按照文章顺序,二三可以根据情况交换
一. context用途
context用于停止goroutine,协调多个goroutine的取消,设置超时取消等等。基于channel和select来实现停止,另外还可以用context在不同的goroutine中传递数据。其中停止goroutine是context的核心。停止goroutine的基本原理: 使用一个channel,在多个goroutine中使用select从channel中取值,context中实际上并不会放任何值到channel中而是关闭channel,这样就channel就不会阻塞,select就能走到case <-ctx.Done()这个分支:
源码使用例子:
//不停的将拿到的返回值v放到out这个channel中,直到发生错误或者收到取消信号
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:
}
}
}
如果doSomething只执行一次还需要用context吗?我觉得不需要,不过要对错误判断,出错则退出goroutine
二.context整体结构
context中结构体和接口之间的关系如图所示,图中只给出了直接关系。没有间接关系,比如timerCtx结构体内部有cancelCtx匿名字段,实际上相当于它也实现了Context和canceler接口。组合关系:结构体中嵌入了匿名字段(例如valueCtx中嵌入了Context字段)实现:实现接口
![103da80265348bf28899850a23c142fe.png](https://i-blog.csdnimg.cn/blog_migrate/3d23c154614836903dcc5d286dd15245.jpeg)
接口和结构体的具体定义: Context:
//Context 上下文管理接口
type Context interface {
//返回一个-<chan struct{} 如果context实例是不可取消的,那么返回nil,比如空Context,valueCtx
Done() <-chan struct{}
//根据key拿到存储在context中的value
//递归查找如果当前节点没有找到会往父节点
Value(key interface{}) interface{}
//返回任务取消的原因
Err() error
//返回任务执行的截止时间
//非timerCtx类型则返回nil
Deadline() (deadline time.Time, ok bool)
}
canceler
//canceler 取消context的接口
type canceler interface {
cancel(removeFromParent bool, err error)
Done() <-chan struct{}
}
valueCtx
// valueContext 用于存储key value
// 不可取消的context
type valueCtx struct {
Context
key interface{}
value interface{}
}
cancelCtx
//cancelCtx