深入理解golang:Context (3)

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 也会被关闭。

newCancelCtx()方法 func newCancelCtx(parent Context) cancelCtx {     return cancelCtx{Context: parent} }

初始化cancelCtx结构体

propagateCancel()方法

这个函数主要作用是当parent context取消时候,进行child context的取消,这有2种模式:

parent取消的时候通知child进行cancel取消
2.parent取消的时候调用child的层层递归取消

// propagateCancel arranges for child to be canceled when parent is. func propagateCancel(parent Context, child canceler) { // 父节点是空的,直接返回     if parent.Done() == nil {         return // parent is never canceled     }     if p, ok := parentCancelCtx(parent); ok {         p.mu.Lock()         if p.err != nil {             // parent has already been canceled             child.cancel(false, p.err)//父节点已经取消,它的子节点也需要取消         } else { //父节点未取消             if p.children == nil {                 p.children = make(map[canceler]struct{})             } // 把这个child放到父节点上             p.children[child] = struct{}{}         }         p.mu.Unlock()     } else { // 如果没有找到可取消的父 context。新启动一个协程监控父节点或子节点取消信号         go func() {             select { // 保证父节点被取消的时候子节点会被取消             case <-parent.Done():                 child.cancel(false, parent.Err())             case <-child.Done():             }         }()     } } parentCancelCtx

这个函数识别三种类型的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) } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsffzy.html