1. 程式人生 > >Go語言-Context上下文實踐

Go語言-Context上下文實踐

opera and lur deadline dst turn function 存在 AI

使用 Context 的程序包需要遵循如下的原則來滿足接口的一致性以及便於靜態分析

1.不要把 Context 存在一個結構體當中,顯式地傳入函數。Context 變量需要作為第一個參數使用,一般命名為ctx

2.即使方法允許,也不要傳入一個 nil 的 Context ,如果你不確定你要用什麽 Context 的時候傳一個 context.TODO

3.使用 context 的 Value 相關方法只應該用於在程序和接口中傳遞的和請求相關的元數據,不要用它來傳遞一些可選的參數

4.同樣的 Context 可以用來傳遞到不同的 goroutine 中,Context 在多個goroutine 中是安全的

方法說明

  • Done 方法在Context被取消或超時時返回一個close的channel,close的channel可以作為廣播通知,告訴給context相關的函數要停止當前工作然後返回。

當一個父operation啟動一個goroutine用於子operation,這些子operation不能夠取消父operation。下面描述的WithCancel函數提供一種方式可以取消新創建的Context.

Context可以安全的被多個goroutine使用。開發者可以把一個Context傳遞給任意多個goroutine然後cancel這個context的時候就能夠通知到所有的goroutine。

  • Err方法返回context為什麽被取消。

  • Deadline返回context何時會超時。

  • Value返回context相關的數據。
  • context 包已經給我們提供了兩個,一個是 Background(),一個是 TODO(),這兩個函數都會返回一個 Context 的實例。只是返回的這兩個實例都是空 Context。BackGound是所有Context的root,不能夠被cancel。

實例1

這個例子傳遞一個上下文,它有一個任意的截止期,它告訴一個阻塞函數,一旦它到達它,它就應該放棄它的工作。

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    d := time.Now().Add(50 * time.Millisecond)
    ctx, cancel := context.WithDeadline(context.Background(),d)
    // Even though ctx will be expired, it is good practice to call its
    // cancelation function in any case. Failure to do so may keep the
    // context and its parent alive longer than necessary.
    defer cancel()
    select {
        case <- time.After(1 * time.Second):
            fmt.Println("overslept")
        case <- ctx.Done():
            fmt.Println(ctx.Err())
    }
}

運行結果

context deadline exceeded

實例2

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    d := time.Now().Add(50 * time.Second)
    ctx, cancel := context.WithDeadline(context.Background(),d)
    // Even though ctx will be expired, it is good practice to call its
    // cancelation function in any case. Failure to do so may keep the
    // context and its parent alive longer than necessary.
    defer cancel()
    select {
        case <- time.After(1 * time.Second):
            fmt.Println("overslept")
        case <- ctx.Done():
            fmt.Println(ctx.Err())
    }
}

運行結果

overslept

實例3

package main

import (
    "context"
    "fmt"
)

func main() {
    // gen generates integers in a separate goroutine and
    // sends them to the returned channel.
    // The callers of gen need to cancel the context once
    // they are done consuming generated integers not to leak
    // the internal goroutine started by gen.
    gen := func(ctx context.Context) <-chan int {
            dst := make(chan int)
            n := 1
            go func() {
        for {
            select {
                case <-ctx.Done():
                    return // returning not to leak the goroutine
                case dst <- n:
                    n++
            }
        }
            }()

            return dst
    }

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel() // cancel when we are finished consuming integers

    for n := range gen(ctx) {
        fmt.Println(n)
        if n == 5 {
            break
        }
    }
}

運行結果

1
2
3
4
5

實例4

package main

import (
    "fmt"
    "context"
)

func main() {
    type favContextKey string

    f := func(ctx context.Context, k favContextKey) {
        if v := ctx.Value(k); v != nil {
            fmt.Println("found value:", v)
            return
        }
        fmt.Println("key not found:", k)
    }

    k := favContextKey("language")
    ctx := context.WithValue(context.Background(), k, "Go")
    f(ctx, k)
    f(ctx, favContextKey("color"))
}

運行結果

found value: Go
key not found: color

實例5

package main

import (
    "fmt"
    "context"
)

func main() {

    f := func(ctx context.Context, k string) {
        if v := ctx.Value(k); v != nil {
            fmt.Println("found value:", v)
            return
        }
        fmt.Println("key not found:", k)
    }

    ctx := context.WithValue(context.Background(), "language", "Go")
    f(ctx, "language")
    f(ctx, "color")
}

運行結果

found value: Go
key not found: color

Go語言-Context上下文實踐