上下文 context.Context Go 语言中用来设置截止日期、同步信号,传递请求相关值的结构体

树形结构

context与goroutine树

context 包中最常用的方法还是 context.Background、context.TODO,这两个方法都会返回预先初始化好的私有变量 background 和 todo,它们会在同一个 Go 程序中被复用

这两个私有变量都是通过 new(emptyCtx) 语句初始化的,它们是指向私有结构体 context.emptyCtx 的指针,这是最简单、最常用的上下文类型:

这两个变量都是emptyCtx类型,这个两个context,永远不会取消,没有value,没有deadline

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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
}

context.Background 是上下文的默认值,所有其他的上下文都应该从它衍生出来; context.TODO 应该仅在不确定应该使用哪种上下文时使用;

cancelFunc 只在第一次调用时生效

context.WithCancel() 方法

context.WithCancel() 必须传递一个非nil的父context,很好理解,如果父context取消了,那么当前context及其子context都必须取消,那么这点需要委托父context实现

当 parent.Done() == nil,也就是 parent 不会触发取消事件时,当前函数会直接返回;
当 child 的继承链包含可以取消的上下文时,会判断 parent 是否已经触发了取消信号;
    如果已经被取消,child 会立刻被取消;
    如果没有被取消,child 会被加入 parent 的 children 列表中,等待 parent 释放取消信号;
当父上下文是开发者自定义的类型、实现了 context.Context 接口并在 Done() 方法中返回了非空的管道时;
    运行一个新的 Goroutine 同时监听 parent.Done() 和 child.Done() 两个 Channel;
    在 parent.Done() 关闭时调用 child.cancel 取消子上下文;

context.WithTimeout() 和 context.WithDeadline()

WithTimeout() 调用 withDeadline()

返回一个timerCtx()

三大类ctx:

emptyCtx、cancelCtx、timerCtx

timerCtx继承了(备注是embed)cancelCtx