context package study notes

Context is used to control the life cycle of a request, as well as one of the data sharing in the cycle package.

data plane

Dependency valueCtx, is mapa

type valueCtx struct {
    Context
    key, val interface{}
}

Read the latest updated value through recursive matching (considering that there should be not much data in a request cycle, recursive query should be acceptable)

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

Data is written by nesting.

func WithValue(parent Context, key, val interface{}) Context {
    ...
    return &valueCtx{parent, key, val}
}

The life cycle

ContextThe management of the life cycle, or the implementation of the notification mechanism on exit, is mainly dependent on cancelCtx.

type cancelCtx struct {
    Context

    mu       sync.Mutex            // protects following fields
    done     chan struct{}         // created lazily, closed by first cancel call
    children map[canceler]struct{} // set to nil by the first cancel call
    err      error                 // set to non-nil by the first cancel call
}

When it is cancelCtxfirst Contextderived from , the background goroutinewill synchronize 退出events by means of . selectDetect the exit by parent, then exit

go func() {
    select {
        case <-parent.Done():
            child.cancel(false, parent.Err())
        case <-child.Done(): // block 机制,避免立即退出
    }
}()

If it is derived from the derived object again, the derivation relationship is maintained through the childrenfield . When parentExit, to actively exit all derivationsContext

for child := range c.children {
    // NOTE: acquiring the child's lock while holding parent's lock.
    child.cancel(false, err)
}

cancelthe main logic of

if c.done == nil {
    c.done = closedchan
} else {
    close(c.done)
}

When channelis closed, all other selectlistening routinewill perceive, thus realizing the notification mechanism.

WithDeadlineOn this basis, a timermechanism to realize its own active exit through the background.

type timerCtx struct {
    cancelCtx
    timer *time.Timer // Under cancelCtx.mu.

    deadline time.Time
}

c.timer = time.AfterFunc(d, func() {
            c.cancel(true, DeadlineExceeded)
        })

The main logic is almost the same

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325984350&siteId=291194637