一、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