timerCtx嵌入了cancelCtx结构体,所以cancelCtx的方法也可以使用。
timerCtx主要是用于实现WithDeadline和WithTimeout两个context实现,其继承了cancelCtx结构体,同时还包含一个timer.Timer定时器和一个deadline终止实现。Timer会在deadline到来时,自动取消context。
cancel()函数:
func (c *timerCtx) cancel(removeFromParent bool, err error) { c.cancelCtx.cancel(false, err) //由于继承了cancelCtx,这里调用了cancelCtx的cancel()方法 if removeFromParent { // Remove this timerCtx from its parent cancelCtx's children. removeChild(c.cancelCtx.Context, c) } c.mu.Lock() if c.timer != nil { c.timer.Stop()//停止定时器 c.timer = nil } c.mu.Unlock() }这个函数继承了cancelCtx的方法cancel(),然后后面进行自身定时器Stop()的操作,这样就可以实现取消操作了。
4.6 valueCtx结构体 type valueCtx struct { Context key, val interface{} }通过key-value来进行值保存
func (c *valueCtx) String() string { return contextName(c.Context) + ".WithValue(type " + reflectlite.TypeOf(c.key).String() + ", val " + stringify(c.val) + ")" } func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) } 4.7 WithCancel方法 WithCancel:创建一个可取消的context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, &c) return &c, func() { c.cancel(true, Canceled) } }传入一个父context(通常是一个background作为根节点),返回新建context。
当 WithCancel 函数返回的 CancelFunc 被调用或者是父节点的 done channel 被关闭(父节点的 CancelFunc 被调用),此 context(子节点) 的 done channel 也会被关闭。
初始化cancelCtx结构体
propagateCancel()方法这个函数主要作用是当parent context取消时候,进行child context的取消,这有2种模式:
parent取消的时候通知child进行cancel取消
2.parent取消的时候调用child的层层递归取消
这个函数识别三种类型的Context:cancelCtx,timerCtx,valueCtx
func parentCancelCtx(parent Context) (*cancelCtx, bool) { for { switch c := parent.(type) { case *cancelCtx: return c, true // 找到最近支持cancel的parent,由parent进行取消操作的调用 case *timerCtx: return &c.cancelCtx, true // 找到最近支持cancel的parent,由parent进行取消操作的调用 case *valueCtx: parent = c.Context // 递归 default: return nil, false } } } 4.8 按时间取消的函数WithTimeout
WithDeadline
WithTimeout是直接调用WithDeadline函数,传入deadline是当前时间+timeout的时间,也就是从现在开始经过timeout时间就算超时。也就是说,WithDeadline用的是绝对时间。
WithTimeout(): func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } WithDeadline() func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { if cur, ok := parent.Deadline(); ok && cur.Before(d) { // The current deadline is already sooner than the new one. return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), deadline: d, } // 监听parent的取消,或者向parent注册自身 propagateCancel(parent, c) dur := time.Until(d) if dur <= 0 { // 已经过期 c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(false, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { c.timer = time.AfterFunc(dur, func() { c.cancel(true, DeadlineExceeded) }) } return c, func() { c.cancel(true, Canceled) } }