一、Context功能
- 控制goroutine超时退出
- 在goroutine传递一些变量
二、Context包的主要结构
-
Context接口
type Context interface { // 调用此方法返回该context超时应该取消的时间点,如果ok=true,说明设置了超时取消的时间为deadline,如果ok=false则未设置。 Deadline() (deadline time.Time, ok bool) // Done方法返回一个关闭的channel当工作完成后,如果工作为完成应该返回nil(golang官方有篇文章([https://blog.golang.org/pipelines](https://blog.golang.org/pipelines))描写怎样用channel来作为取消功能)。 Done() <-chan struct{} // 如果Done还没有被关闭返回nil,如果关闭了则返回一个非空的错误来解释取消原因。 Err() error // 存储在context的键值对 Value(key interface{}) interface{} }
-
Context接口实现
2.1. emptyCtx// emptyCtx 不能被取消,不能存储值,不能设置超时 type emptyCtx int // 以下是emptyCtx实现Context接口的具体代码,没有任何的逻辑,都是空。 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 interface{}) interface{} { return nil } // background, todo都是emptyCtx的实例,backgroud一般用于整个程序初始化的时候的context,todo一般用于不知道用哪个context时使用它。 var ( background = new(emptyCtx) todo = new(emptyCtx) )
2.2 cancelCtx
// cancelCtx实现了Context,也实现了canceler,它可以被取消,同时也把子context也取消。 type cancelCtx struct { Context mu sync.Mutex // 当并发时控制以下字段 done chan struct{} // 懒惰创建,在第一次调用cancel时会关闭 children map[canceler]struct{} // 在第一次调用cancel时会设置为nil err error // 在第一次调用cancel时会被设置成非空 } // canceler接口 type canceler interface { cancel(removeFromParent bool, err error) Done() <-chan struct{} } // cancelCtx实现canceler接口的Done方法 func (c *cancelCtx) Done() <-chan struct{} { c.mu.Lock() if c.done == nil { c.done = make(chan struct{}) } d := c.done c.mu.Unlock() return d } // cancelCtx实现canceler接口的cancel方法 func (c *cancelCtx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.err != nil { c.mu.Unlock() return // already canceled } c.err = err if c.done == nil { c.done = closedchan } else { close(c.done) } for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. child.cancel(false, err) } c.children = nil c.mu.Unlock() if removeFromParent { removeChild(c.Context, c) } } // cancelCtx实现过程在WithCancel函数 // 1.WithCancel函数返回一个cancelCtx和cancelFunc func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, &c) return &c, func() { c.cancel(true, Canceled) } } // 2.WithCancel函数内部会将cancelCtx注册到父的context中(如果父context是可取消的context) 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{}) } p.children[child] = struct{}{} } p.mu.Unlock() } else { // 这里表示只会取消cancelCtx类型的context go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() } }
2.3 timerCtx
// timerCtx接口嵌入(继承)cancelCtx type timerCtx struct { cancelCtx timer *time.Timer // Under cancelCtx.mu. deadline time.Time }
2.4 valueCtx
// valueCtx携带key-value,嵌入Context接口 type valueCtx struct { Context key, val interface{} }
-
重要的包级函数
3.1 WithCancel(parent Context) (ctx Context, cancel CancelFunc):返回context和取消函数。
3.2 WithDeadline(parent Context, d time.Time) (Context, CancelFunc):返回context和取消函数,并且设置超时自动取消的时间。
3.3 WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) :和WithDeadline相似,但是时间参数换成了相对时间。
3.4 WithValue(parent Context, key, val interface{}) Context:传入key-value,返回context