Context上下文简介
当 一个请求被取消或者发生超时时,为了防止资源泄露,这个请求上 的所有goroutine 都应该被退出来。通过context传入,可以 将一些取消信息或者超时信息传递给其他协。
context 相当于 简洁得管理了goroutines的生命周期,context包定义了 不同上下文类型,它跨API边界和进程之间传递截止日期、取消信号和其他请求范围的值。
Context源码解读
1、Context接口
type Context interface {
Deadline() (deadline time.Time, ok bool)
// Deadline()方法 返回当前上下文的截至时间,即该上下文应该被取消的时间
// 如果没有设置超时时间,则返回的ok为false
// Done() 方法方法,当struct通道,有写出时实现
Done() <-chan struct{
}
// 当代表此上下文完成的工作应取消时,Done返回一个被关闭的通道,如果无法取消此上下文,则Done可能返回nil
//cancel函数返回后,Done通道的关闭可能会异步进行。
//WithCancel安排在调用cancel时关闭Done;
//WithDeadline安排在期限届满时关闭;
//WithTimeout安排在超时结束时关闭Done。
// Err()方法,代表被关闭的原因
Err() error
// 如果Done尚未关闭,Err返回nil。 如果关闭了Done,Err将返回一个非nil错误,解释原因:如果上下文被取消,则是取消错误;如果上下文的截止日期已过,则超出截止时间错误。
// Value()方法,返回与 key 相关了的值,不存在返回 nil
Value(key interface{
}) interface{
}
// 仅对传输进程和API边界的请求范围的数据使用上下文值,而不是为了给函数传递可选参数。
// key标识上下文中的特定值,希望在上下文中存储值的函数通常在全局变量中分配一个key,然后将该key用作argument传给context.WithValue and Context.Value
Done()方法 在上下文被取消或超时时会关闭当前监听的通道,表示上下文不再监听,因此关闭可以 作为广播通知,告诉context相关的函数要停止当前工作然后退出。
创建Context时会返回CancelFunc函数,调用CancelFunc函数以及到了超时时间,会关闭Done()方法监听的channel,所以Done()需要放到select中。 父Context取消时,其子Context也会被取消。但是子Context取消时,其父Context不会被取消
Done用于select语句:Stream()使用DoSomething()生成值,并将其发送到输出,直到DoSomething返回错误或ctx.Done关闭
// 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:
}
}
}
Value()方法通过key获取该key在上下文中关联的值,如果该key没有关联的值,则返回nil,多次调用同一个key,返回的结果是一样的
var userKey key
// NewContext返回一个携带值u的新上下文。
func NewContext(ctx context.Context, u *User) context.Context {
return context.WithValue(ctx, userKey, u)
}
// FromContext返回存储在上下文中的用户值(如果有)。
func FromContext(ctx context.Context) (*User, bool) {
u, ok := ctx.Value(userKey).(*User)
return u, ok
}
2、deadlineExceededError 对象
type deadlineExceededError struct{
}
// (截止时间超时)对象 Error报错方法:返回字符串
func (deadlineExceededError) Error() string {
return "context deadline exceeded" }
// (截止时间超时)对象 Timeout超时方法:返回 是否超时
func (deadlineExceededError) Timeout() bool {
return true }
// (截止时间超时)对象 Temporary暂停方法:返回 是否暂停
func (deadlineExceededError) Temporary() bool {
return true }
3、 emptyCtx对象
empty是空的Context,但是实现了Context的接口。emptyCtx没有超时时间,不能被取消,也不能存储任何额外信息,所以emptyCtx常用来作为Context的根节点
// 空上下文emptyCtx对象(int类型),以下实现了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
}
// 空上下文对象的String方法:如果空上下文对象是background、或者todo。。。,返回不同字符串
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}
由于emptyCtx是不能外部访问,所以我们只能用Background和TOD