// WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete.
// A cancelCtx can be canceled. When canceled, it also cancels any children // that implement canceler. type cancelCtx struct { Context
mu sync.Mutex // protects following fields done chanstruct{} // created lazily, closed by first cancel call done是一個channel,用來 傳遞關閉信號 children map[canceler]struct{} // set to nil by the first cancel call children是一個map,存儲了當前context節(jié)點下的子節(jié)點 err error // set to non-nil by the first cancel call err用于存儲錯誤信息 表示任務結束的原因 }
// A canceler is a context type that can be canceled directly. The // implementations are *cancelCtx and *timerCtx. type canceler interface { cancel(removeFromParent bool, err error) Done() <-chanstruct{} }
// closedchan is a reusable closed channel. var closedchan = make(chanstruct{})
funcinit() { close(closedchan) }
// cancel closes c.done, cancels each of c's children, and, if // removeFromParent is true, removes c from its parent's children. /** * 1、cancel(...)當前Ctx的子節(jié)點 * 2、從父節(jié)點中移除該Ctx **/ 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
// Done is provided for use in select statements: // // // Stream generates values with DoSomething and sends them to out // // until DoSomething returns an error or ctx.Done is closed. // func Stream(ctx context.Context, out chan<- Value) error { // for { // v, err := DoSomething(ctx) // if err != nil { // return err // } // select { // case <-ctx.Done(): // return ctx.Err() // case out <- v: // } // } // } // // See https://blog./pipelines for more examples of how to use // a Done channel for cancellation. Done() <-chanstruct{}
// If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error explaining why: // Canceled if the context was canceled // or DeadlineExceeded if the context's deadline passed. // After Err returns a non-nil error, successive calls to Err return the same error. Err() error
for { select { case res := <-ctx.Done(): fmt.Println("res:", res) return case res2 := <-cuiChan: fmt.Println("res2:", res2) default: fmt.Println("I am working!") time.Sleep(time.Second) } } }
make(chanstruct{})后不為nil!??! I am working! res2: {} I am working! I am working! I am working! I am working! res: {}
而如果 不向沒有緩存的cuiChan寫入數(shù)據,直接close,即
package main
import ( "context" "fmt" "time" )
funcdosomething(ctx context.Context) {
var cuiChan = make(chanstruct{})
//go func() { // cuiChan <- struct{}{} //}()
close(cuiChan)
for { select { case res := <-ctx.Done(): fmt.Println("res:", res) return case res2 := <-cuiChan: fmt.Println("res2:", res2) default: fmt.Println("I am working!") time.Sleep(time.Second) } } }