这篇文章 讲的太好了,自己记录一下加深印象
主要用途:用于在异步场景并发协调以及对goruntinue的生命周期进行控制,传递取消信号,超时,截止时间,并且具有一定的数据存储能力
核心数据结构
1 2 3 4 5 6 type Context interface { Deadline() (deadline time.Time, ok bool ) Done() <-chan struct {} Err() error Value(key any) any }
emptyCtx
根基:是所有context的根
1 2 3 4 5 6 7 8 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 any) any {return }
常用的context.BackGround()与context.TODO()方法返回的都是emptyCtx
cancelCtx
1 2 3 4 5 6 7 8 9 10 11 type cancelCtx struct { Context mu sync.Mutex done atomic.Value children map [canceler]struct {} err error } type canceler interface { cancel(removeFromParent bool , err error ) Done() <-chan struct {} }
内嵌了一个context,所以可见cancelCtx必定是某个context的子context
children: 此cancelCtx的子context
Deadline:cancelCtx并没有实现这个方法,只是内嵌了有Deadline()方法的Context,直接调用会报错
Done:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func (c *cancelCtx) Done() <-chan struct {} { d := c.done.Load() if d != nil { return d.(chan struct {}) } c.mu.Lock() defer c.mu.Unlock()d = c.done.Load() if d == nil { d = make (chan struct {}) c.done.Store(d) } return d.(chan struct {})}
Err1 2 3 4 5 6 func (c *cancelCtx) Err() error { c.mu.Lock() err := c.err c.mu.Unlock() return err }
Value1 2 3 4 5 6 func (c *cancelCtx) Value(key any) any { if key == &cancelCtxKey { return c } return value(c.Context, key) }
context.WithCancel
1 2 3 4 5 6 7 8 func WithCancel (parent Context) (ctx Context, cancel CancelFunc) { if parent == nil { panic ("cannot create context from nil parent" ) } c := newCancelCtx(parent) propagateCancel(parent, &c) return &c, func () { c.cancel(true , Canceled) } }
当我们调用 WithCancel 创建它时,它不仅初始化了自己,还必须立刻寻找上级。使用propagateCancel,尝试将新节点加入到父节点的 children 列表中;如果父节点不支持列表(非标准实现),它就启动一个守护协程来通过 Channel 监听父节点的生死。
propagateCancel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 func propagateCancel (parent Context, child canceler) { done := parent.Done() if done == nil { return } select { case <-done: child.cancel(false , parent.Err()) return default : } if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() if p.err != nil { child.cancel(false , p.err) } else { if p.children == nil { p.children = make (map [canceler]struct {}) } p.children[child] = struct {}{} } p.mu.Unlock() } else { atomic.AddInt32(&goroutines, +1 ) go func () { select { case <-parent.Done(): child.cancel(false , parent.Err()) case <-child.Done(): } }() } }
timerCtx
类
1 2 3 4 5 6 type timerCtx struct { cancelCtx timer *time.Timer deadline time.Time }
它在cancel的基础上再进行封装,增加了一个time.Timer用于定时终止context,deadline用于timerCtx的过期时间
timerCtx.cancel
context.WithTimeout & context.WithDeadline
valueCtx
类
1 2 3 4 type valueCtx struct { Context key, val any }
valueCtx.Value()
1 2 3 4 5 6 func (c *valueCtx) Value(key any) any { if c.key == key { return c.val } return value(c.Context, key) }
调用了value内部方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func value (c Context, key any) any { for { switch ctx := c.(type ) { case *valueCtx: if key == ctx.key { return ctx.val } c = ctx.Context case *cancelCtx: if key == &cancelCtxKey { return c } c = ctx.Context case *timerCtx: if key == &cancelCtxKey { return &ctx.cancelCtx } c = ctx.Context case *emptyCtx: return nil default : return c.Value(key) } } }
valueCtx.WithValue()
1 2 3 4 5 6 7 8 9 10 11 12 func WithValue (parent Context, key, val any) Context { if parent == nil { panic ("cannot create context from nil parent" ) } if key == nil { panic ("nil key" ) } if !reflectlite.TypeOf(key).Comparable() { panic ("key is not comparable" ) } return &valueCtx{parent, key, val} }