go系列之context

339 阅读3分钟

简介

英文:Package context defines the Context type, which carries deadlines,cancelation signals, and other request-scoped values across API boundaries and between processes.
翻译:包上下文定义了上下文类型,该类型在API边界之间以及进程之间传递截止日期,取消信号和其他请求范围的值。 context信号传递可以理解为如下图的节点树:

父节点通过层层传递通知所有子孙节点,比如a节点cancel(取消)时,a/b/c/e/f节点都会收到Done(完成信号)进行相应下一步操作,例如清理缓存,退出goroutine等操作,代码示例如下:

func main() {
	ctx_a, cancel := context.WithCancel(context.Background())
	ctx_b, _ := context.WithCancel(ctx_a)
	ctx_c, _ := context.WithCancel(ctx_a)
	ctx_e, _ := context.WithCancel(ctx_c)
	ctx_f, _ := context.WithCancel(ctx_c)

	go run("ctx_b", ctx_b)
	go run("ctx_c", ctx_c)
	go run("ctx_e", ctx_e)
	go run("ctx_f", ctx_f)      
   
	cancel()
	time.Sleep(time.Second)
}

func run(name string, ctx context.Context) {
	select {
	case <-ctx.Done():
		{
		        //do somthing
			fmt.Println(name, "收到信号")
		}
	default:
		fmt.Println("未收到信号")
	}
}

结果:
ctx_c 收到信号
ctx_b 收到信号
ctx_e 收到信号
ctx_f 收到信号

Context 接口

type Context interface {
	//返回设置运行的截止日期,如果返回的ok变量等于false,说明这个context没有设置截至日期,ok等于true时说明context设置了截止日期。
	// 多次调用也只会返回相同的结果。
	Deadline() (deadline time.Time, ok bool)
	//返回一个只读的 channel,一般用来接收父context发送的取消信号。
	Done() <-chan struct{}
	//返回context被取消原因,如果context没有被取消时Err()返回空。
	Err() error
	//用于存储关联数据,键值对
	Value(key interface{}) interface{}
}

Context 继承

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
  • WithCancel:传递一个父 Context,返回子 Context及取消函数。
func main() {
	w := &sync.WaitGroup{}
	w.Add(1)
	ctx_a, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-ctx_a.Done():
			fmt.Println("ctx_a完成了")
			w.Done()
		default:
			fmt.Println("ctx_a没有完成")
		}
	}()
	cancel()
	w.Wait()
}
//输出:
//ctx_a完成了
  • WithDeadline和WithTimeout:传递一个父 Context和截止时间点(时间间隔),返回子 Context及取消函数。到了时间截止点,自动通知context完成,当然你也可以提前调用cancel去取消context。
func main() {
	w := &sync.WaitGroup{}
	w.Add(1)
	//设置5秒之后截止
	ctx_a, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*5))

	go func() {
		i := 0
		for {
			select {
			case <-ctx_a.Done():
				fmt.Println("ctx_a完成了")
				w.Done()
				return
			case <-time.After(time.Second):
				i++
				fmt.Println(i, "秒")
			}
		}

	}()
	//提前调用cancel取消
	//cancel()
	w.Wait()
}
//输出:
//1 秒
//2 秒
//3 秒
//4 秒
//ctx_a完成了
  • WithValue:传递一个父 Context和一对键值,返回子 Context。WithValue主要用于context关联一堆键值数据,它没有取消函数功能。一般通过继承父context来实现取消函数。
func main() {
	w := &sync.WaitGroup{}
	w.Add(1)
	//设置5秒之后截止
	ctx_a, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*5))
	ctx_b := context.WithValue(ctx_a, "name", "ctx_b")

	go func() {
		i := 0
		for {
			select {
			case <-ctx_b.Done():
				fmt.Println(ctx_b.Value("name"), "完成了")
				w.Done()
				return
			case <-time.After(time.Second):
				i++
				fmt.Println(i, "秒")
			}
		}

	}()
	//提前调用cancel取消
	//cancel()
	w.Wait()
}
//输出:
//1 秒
//2 秒
//3 秒
//4 秒
//ctx_b 完成了

emptyCtx

An emptyCtx is never canceled, has no values, and has no deadline.
不能取消,没有存储数据,没有截止日期,说罢了就是一个空的context。

background = new(emptyCtx)
todo       = new(emptyCtx)
  • context.background: 它通常由主要用于初始化和测试使用,并用作传入的顶级上下文。相当于context节点树的根root。
  • context.todo: 当尚不清楚要传递什么context时或者不用的context可以用这个来当中参数

参考

修改时间:2019/11/18