GoLang Context 패키지 상세 설명

9496 단어
원본 링크:http://studygolang.com/articles/5131
프로필
Context 는 go 에서 자주 사용 되 는 패키지 로 구 글 이 공식 개발 했다.특히 흔히 볼 수 있 는 응용 장면 은 하나의 요청 이 파생 된 각 goroutine 간 에 일정한 제약 조건 을 만족 시 켜 유효기간, routline 트 리 종료, 전체 변 수 를 전달 하 는 등 기능 을 실현 해 야 한다.Context 를 사용 하여 컨 텍스트 기능 을 실현 하려 면 매개 변 수 를 입력 하 는 첫 번 째 context. context 형식의 변 수 를 입력 해 야 합 니 다. 우 리 는 소스 코드 의 읽 기와 예제 코드 를 통 해 context 의 용법 을 설명 할 것 입 니 다.
핵심 인터페이스\# #
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() 

기본 오류:
var Canceled = errors.New("context canceled")
var DeadlineExceeded error = deadlineExceededError{}
type deadlineExceededError struct{}

func (deadlineExceededError) Error() string   { return "context deadline exceeded" }
func (deadlineExceededError) Timeout() bool   { return true }
func (deadlineExceededError) Temporary() bool { return true }

빈 Context
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int

func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
    return
}

func (*emptyCtx) Done() 

원본 패키지 에서 두 개의 빈 Context 를 제공 합 니 다.
var (
    background = new(emptyCtx)
    todo       = new(emptyCtx)
)

// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func Background() Context {
    return background
}

// TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context
// parameter). TODO is recognized by static analysis tools that determine
// whether Contexts are propagated correctly in a program.
func TODO() Context {
    return todo
}

canceler##
cancelCtx 구조 체 는 Context 를 계승 하여 canceler 방법 을 실현 했다.
//*cancelCtx   *timerCtx    canceler  ,              cancel
// 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() 

cancel 과 관련 된 방법 을 살 펴 보 겠 습 니 다.
type CancelFunc func()

// WithCancel         parent Context  ,     cancel           Context   Done channel
//                  cancel     (    )
//      parent    cancel   ,          
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
    c := newCancelCtx(parent)
    propagateCancel(parent, &c)
    return &c, func() { c.cancel(true, Canceled) }
}

func newCancelCtx(parent Context) cancelCtx {
    return cancelCtx{
        Context: parent,
        done:    make(chan struct{}),
    }
}

//   cancel
//       parent  (   parent),            cancel parent
//      parent   cancel,       child  cancel 
//   , child          parent children (Context    ,          ,             )
// 
//             cancel parent,       cancel,     goroutine     parent  , cancel   child ,       child  。
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]bool)
            }
            p.children[child] = true
        }
        p.mu.Unlock()
    } else {
        go func() {
            select {
            case 

Deadline 과 TimeOut 은 먼저 cancelCtx 를 계승 하 는 구조 체 를 봅 니 다.
type timerCtx struct {
    cancelCtx //            cancelCtx   ,cancelCtx.Context         
    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, c.deadline.Sub(time.Now()))
}

//  cencelCtx    ,     cancelCtx.cancel,   c.timer  Stop(),  c.timer=nil
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()
}

이 구조 체 에서 파생 된 두 가지 방법:
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
    //   parent deadline     deadline    ,   WithCancel,      deadline   ,   deadline    。
    if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
        // The current deadline is already sooner than the new one.
        return WithCancel(parent)
    }
    c := &timerCtx{
        cancelCtx: newCancelCtx(parent),
        deadline:  deadline,
    }
    //    
    propagateCancel(parent, c)

    //         , cancel    
    d := deadline.Sub(time.Now())
    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 {
        //     cancel  ,   deadline  cancel    
        c.timer = time.AfterFunc(d, func() {
            c.cancel(true, DeadlineExceeded)
        })
    }
    return c, func() { c.cancel(true, Canceled) }
}


// timeout deadline    
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
    return WithDeadline(parent, time.Now().Add(timeout))
}

Value Value Ctx 는 주로 메타 데 이 터 를 전달 하 는 데 사 용 됩 니 다. WithValue () 를 통 해 계승 을 전달 하고 Value () 를 통 해 읽 습 니 다. 간단 하고 군말 하지 않 습 니 다.
func WithValue(parent Context, key interface{}, val interface{}) Context {
    return &valueCtx{parent, key, val}
}

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)
}

사용 원칙:\#\#
  • Programs that use Contexts should follow these rules to keep interfaces consistent across packages and enable static analysis tools to check context propagation: Context 패 키 지 를 사용 하려 면 다음 과 같은 원칙 에 따라 인터페이스의 일치 성과 정적 분석 에 편리 해 야 합 니 다
  • Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx: Context 를 하나의 구조 체 에 존재 하지 말고 함수 에 명시 적 으로 전달 하지 마 세 요.Context 변 수 는 첫 번 째 매개 변수 로 사용 해 야 합 니 다. 일반적으로 ctx
  • 라 고 명명 합 니 다.
    func DoSomething(ctx context.Context, arg Arg) error {
     ... use ctx ...
     }
    
  • Do not pass a nil Context, even if a function permits it. Pass context. TODO if you are unsure about which Context to use. 방법 이 허락 되 더 라 도 nil Context 에 들 어가 지 마 세 요. 어떤 Context 를 사용 할 지 확실 하지 않 을 때 context. TODO
  • Use context Values only for request - scoped data that transists processes and API, not for passing optional parameters to functions. context 를 사용 하 는 Value 관련 방법 은 프로그램 과 인터페이스 에서 전달 되 는 요청 과 관련 된 메타 데이터 에 만 사용 되 며 선택 가능 한 매개 변수
  • 를 전달 하지 마 십시오.
  • The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines. 같은 Context 는 서로 다른 goroutine 에 전달 할 수 있 습 니 다. Context 는 여러 goroutine 에서 안전 합 니 다
  • 사용 요령:\#\#
    사실 그 자체 가 매우 간단 합 니 다. 이 가방 을 가 져 온 후에 Context 대상 을 초기 화하 고 모든 자원 접근 방법 에서 호출 한 다음 에 사용 할 때 Context 대상 이 Cancel 에 있 는 지 확인 하고 바 인 딩 된 자원 을 방출 합 니 다.다음 과 같다.http://blog.golang.org/context예제 프로그램) 최종 cancel 을 초기 화하 고 설정 합 니 다.
    func handleSearch(w http.ResponseWriter, req *http.Request) {
        // ctx is the Context for this handler. Calling cancel closes the
        // ctx.Done channel, which is the cancellation signal for requests
        // started by this handler.
        var (
            ctx    context.Context
            cancel context.CancelFunc
        )
        timeout, err := time.ParseDuration(req.FormValue("timeout"))
        if err == nil {
            // The request has a timeout, so create a context that is
            // canceled automatically when the timeout expires.
            ctx, cancel = context.WithTimeout(context.Background(), timeout)
        } else {
            ctx, cancel = context.WithCancel(context.Background())
        }
        defer cancel() // Cancel ctx as soon as handleSearch returns.
    

    중간 과정 에서 전달 하고 자원 관련 작업 을 할 때 ctx. Done () 에서 값 이 전달 되 었 는 지 판단 하 며 Done () 의 사용 에 대해 참고 해 야 합 니 다.http://blog.golang.org/pipelines 예상 치 못 하 게 끝 난 프로그램의 반환 값 은 대응 하 는 ctx. Err () 여야 합 니 다.
    func httpDo(ctx context.Context, req *http.Request, f func(*http.Response, error) error) error {
        // Run the HTTP request in a goroutine and pass the response to f.
        tr := &http.Transport{}
        client := &http.Client{Transport: tr}
        c := make(chan error, 1)
        go func() { c 

    좋은 웹페이지 즐겨찾기