golang中context的理解

81 阅读1分钟

image.png

golang的context本身是按照链式结构组织的,每种context的成员里面都有一个指向父context的结构,源码如下:

type cancelCtx struct {
	Context //父context

	mu       sync.Mutex            // protects following fields
	done     atomic.Value          // of chan struct{}, created lazily, closed by first cancel call
	children map[canceler]struct{} // set to nil by the first cancel call
	err      error                 // set to non-nil by the first cancel call
}

type timerCtx struct {
	cancelCtx //父context
	timer *time.Timer // Under cancelCtx.mu.

	deadline time.Time
}

type valueCtx struct {
	Context  //父context
	key, val interface{}
}

但是,timerCtx和cancelCtx还额外维护了一个map,把所有的子context的cancel方法都存在里面了,这样,父context取消的时候,子context也会跟着取消。

使用context的一个坑,在rpc接口中,如果有长时间执行的任务,在rpc接口返回以后还需要执行,那么,需要自己重新生产一个context,一般的rpc框架,在接口执行完以后,都会取消掉这个context。

context的done本质就是一个标识位,只是做了一些封装而已。

打日志的时候,如果需要打印context中的值,并且context中赋了很多值,有可能会造成性能问题,因为需要回溯的context个数很多。解决办法是自己包一层日志相关的值,放到map里面,然后把map放到context里面。