golang context 源码阅读

前端之家收集整理的这篇文章主要介绍了golang context 源码阅读前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Context 派生:

ctx,_ := context.WithTimeout(context.Background(),(10 * time.Second))

源码分析:

// WithTimeout returns WithDeadline(parent,time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it,so code should
// call cancel as soon as the operations running in this Context complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result,error) {
// ctx,cancel := context.WithTimeout(ctx,100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
func WithTimeout(parent Context,timeout time.Duration) (Context,CancelFunc) {
    return WithDeadline(parent,time.Now().Add(timeout))
}

func WithDeadline(parent Context,deadline time.Time) (Context,CancelFunc) {
    if cur,ok := parent.Deadline(); ok && cur.Before(deadline) {
        // 被派生的context设置了超时且当前时间小于超时时间
        // The current deadline is already sooner than the new one.
        return WithCancel(parent)
    }
    c := &timerCtx{
        cancelCtx: newCancelCtx(parent),deadline:  deadline,}
    // check deadline passed
    propagateCancel(parent,c)
    d := time.Until(deadline)
    if d <= 0 {
        c.cancel(true,DeadlineExceeded) // deadline has already passed
        return c,func() { c.cancel(true,Canceled) }
    }
    c.mu.Lock()
    defer c.mu.Unlock()
    if c.err == nil {
        // timeout and cancel context
        c.timer = time.AfterFunc(d,func() {
            c.cancel(true,DeadlineExceeded)
        })
    }
    return c,Canceled) }
}

func WithCancel(parent Context) (ctx Context,cancel CancelFunc) {
    // 创建新的context
    c := newCancelCtx(parent)
    propagateCancel(parent,&c)
    return &c,Canceled) }
}

func propagateCancel(parent Context,child canceler) {
    if parent.Done() == nil {
        return // parent is never canceled
    }
    // get partner cancel context
    if p,ok := parentCancelCtx(parent); ok {
        p.mu.Lock()
        if p.err != nil {
            // parent has already been canceled
            child.cancel(false,p.err)
        } else {
            // build with map
            if p.children == nil {
                p.children = make(map[canceler]struct{})
            }
            p.children[child] = struct{}{}
        }
        p.mu.Unlock()
    } else {
        go func() {
            select {
            // if parent close,then child close()
            case <-parent.Done():
                child.cancel(false,parent.Err())
            case <-child.Done():
            }
        }()
    }
}
//判断parent是否为cancelCtx类型
func parentCancelCtx(parent Context) (*cancelCtx,bool) {
    for {
        switch c := parent.(type) {
        case *cancelCtx:
            return c,true
        case *timerCtx:
            return &c.cancelCtx,true
        case *valueCtx:
            parent = c.Context
        default:
            return nil,false
        }
    }
}

context 类型:
1. 可cancel的context:

// A cancelCtx can be canceled. When canceled,it also cancels any children
// that implement canceler.
type cancelCtx struct {
    Context

    done chan struct{} // closed by the first cancel call.

    mu       sync.Mutex
    children map[canceler]struct{} // set to nil by the first cancel call
    err      error                 // set to non-nil by the first cancel call
}

// return channel !!!
func (c *cancelCtx) Done() <-chan struct{} {
    return c.done
}

func (c *cancelCtx) Err() error {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.err
}

func (c *cancelCtx) String() string {
    return fmt.Sprintf("%v.WithCancel",c.Context)
}

// cancel closes c.done,cancels each of c's children,and,if
// removeFromParent is true,removes c from its parent's children.
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
    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)
    }
}
  1. 带着计时的可cancel的context(匿名cancel的context)
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to // implement Done and Err. It implements cancel by stopping its timer then // delegating to cancelCtx.cancel.
type timerCtx struct {
    cancelCtx
    timer *time.Timer // Under cancelCtx.mu.

    deadline time.Time
}

func (c *timerCtx) Deadline() (deadline time.Time,ok bool) {
    return c.deadline,true
}

func (c *timerCtx) String() string {
    return fmt.Sprintf("%v.WithDeadline(%s [%s])",c.cancelCtx.Context,c.deadline,time.Until(c.deadline))
}

func (c *timerCtx) cancel(removeFromParent bool,err error) {
    c.cancelCtx.cancel(false,err)
    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()
}

key-value pair

// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type valueCtx struct {
    Context
    key,val interface{}
}

func (c *valueCtx) String() string {
    return fmt.Sprintf("%v.WithValue(%#v,%#v)",c.Context,c.key,c.val)
}

func (c *valueCtx) Value(key interface{}) interface{} {
    if c.key == key {
        return c.val
    }
    return c.Context.Value(key)
}

猜你在找的Go相关文章