golangにおけるContextの利用シーンまとめ

go 1.7 で導入された親コルーチンが子コルーチンを閉じたい場合、そのコンテキストの cancel 関数が呼び出され、そのチャネルにシグナルが送信されます。

Context の機能は、メソッドへの終了シグナルの送信、複数のメソッドへの共通データの受け渡しという 2 つの側面に反映されます。

Context の主な 4 つの構造、CancelContext、TimeoutContext、DeadLineContext、および ValueContext の使用

該当するシナリオは何ですか?

何らかの理由(タイムアウトまたは強制終了)で、このゴルーチンの計算タスクを中止したい場合は、このコンテキストを使用できます。

一般的な同時実行制御コンポーネント: waitGroup、Context

具体的な使用シナリオ:

1. RPC の使用、http リクエスト。withCancel を使用したタイムアウトは 1 つのカテゴリにグループ化されます。cancel() は複数回呼び出され、コンテキスト パッケージ内の cancel 呼び出しは冪等です。安心して何度でも呼び出せます。非同期並列制御。特定の呼び出しが失敗しても、他の呼び出しには影響しません。

コード例

package main

import (
    "context"
    "fmt"
    "math/rand"
    "net/http"
    "os"
    "time"
)

func main(){
//context控制并发  WithCancel  cancel()
    ctx,cancel := context.WithCancel(context.Background())
   go Worker(ctx,"01")
   go Worker(ctx,"02")
   go Worker(ctx,"03")
    time.Sleep(time.Second * 5)
    fmt.Println("stop all")
    cancel()
    time.Sleep(time.Second * 1)
}

func Worker(ctx context.Context,name string ) {
    for {
        select{
        case <- ctx.Done():
            fmt.Println(name," stop the goroutine!")
            return
        default:
            fmt.Println(name," ing")
            time.Sleep(time.Second *1)
        }
    }
}

//结果打印:
//01  ing
//02  ing
//02  ing
//03  ing
//01  ing
//01  ing
//02  ing
//03  ing
//02  ing
//01  ing
//03  ing
//01  ing
//02  ing
//03  ing
//stop all
//02  stop the goroutine!
//03  stop the goroutine!
//01  stop the goroutine!

context WithCancel はコントロールをキャンセルし、キャンセル信号を送信して、このロジックから発生するすべてのゴルーチンが正常にキャンセルされることを確認します。

2. HTTP サーバーは、相互に WithValue データの転送を要求します。WithContext はインターセプターでよく使用され、Cookie の検証後、公開情報がリクエストに保存され、インターフェイスがそれを独自に取得できます。

コード例

// WithValue 使用
func main(){
    ContextWithValue()
}

func ContextWithValue() {
    rand.Seed(time.Now().Unix())
    ctx := context.WithValue(context.Background(), keyID, rand.Int())
    operation1(ctx)
}

func operation1(ctx context.Context) {
    fmt.Println("operation1 for id:", ctx.Value(keyID), " completed")
    operation2(ctx)
}

func operation2(ctx context.Context) {
    fmt.Println("operation2 for id:", ctx.Value(keyID), " completed")
}

3. タイムアウト要求。rpc は http を呼び出し、WithTimeout WithDeadLine を呼び出します (ファイル io やネットワーク io などの時間のかかる操作では、残り時間が次のステップに進むかどうかを決定するのに十分かどうかを確認できます)

WithDeadLine と withTimeout で渡される時間パラメーターは異なりますが、残りは同じです。

WithTimeout のコード例

import (
    "context"
    "fmt"
    "math/rand"
    "net/http"
    "os"
    "time"
)


// WithTimeout
func main(){
// 创建一个空ctx
    ctx := context.Background()
    // 设置超时时间
    cxt, _ := context.WithTimeout(ctx, 1*time.Millisecond)

    start := time.Now()
    // 创建一个请求 访问谷歌
    req, _ := http.NewRequest(http.MethodGet, "http://baidu.com", nil)
    // 将带有取消方法的ctx和请求关联
    req = req.WithContext(cxt)

    client := &http.Client{}
    res, err := client.Do(req)
    if err!=nil{
        fmt.Println("Request failed:", err ," time ",time.Now().Sub(start))

        return
    }
    fmt.Println("Response received, status code:", res.StatusCode)
}
WithTimeout代码示例
func main(){
    ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second * 4))
    defer cancel()
    copyFileWithDeadline(ctx)
    time.Sleep(time.Second * 5)
}

func copyFileWithDeadline(ctx context.Context)  {
    deadline, ok := ctx.Deadline()
    if ok == false {
        return
    }
    // deadline.Sub(time.Now()) 截止时间与当前时间的差值
    isEnough := deadline.Sub(time.Now()) > time.Second * 5
    if isEnough {
        fmt.Println("copy file")
    } else {
        fmt.Println("isEnough is false return")
        return
    }
}

コンテキスト制御の同時実行コードの例では、コルーチンの実行順序がランダムであることに注意してください。ただし、waitgroup は、確実に順次実行できる同時実行制御です。

package main

import (
    "context"
    "fmt"
    "math/rand"
    "net/http"
    "os"
    "time"
)

func main(){
//context控制并发  WithCancel  cancel()
    ctx,cancel := context.WithCancel(context.Background())
   go Worker(ctx,"01")
   go Worker(ctx,"02")
   go Worker(ctx,"03")
    time.Sleep(time.Second * 5)
    fmt.Println("stop all")
    cancel()
    time.Sleep(time.Second * 1)
}

func Worker(ctx context.Context,name string ) {
    for {
        select{
        case <- ctx.Done():
            fmt.Println(name," stop the goroutine!")
            return
        default:
            fmt.Println(name," ing")
            time.Sleep(time.Second *1)
        }
    }
}

//结果打印:
//01  ing
//02  ing
//02  ing
//03  ing
//01  ing
//01  ing
//02  ing
//03  ing
//02  ing
//01  ing
//03  ing
//01  ing
//02  ing
//03  ing
//stop all
//02  stop the goroutine!
//03  stop the goroutine!
//01  stop the goroutine!

func main(){
// waitgroup来控制并发
    wg := sync.WaitGroup{}
    wg.Add(2)
    go func(){
        fmt.Println("1 job")
        wg.Done()
    }()
    go func(){
        fmt.Println(" 2 job")
        wg.Done()
    }()
    wg.Wait()
    fmt.Println(" end")
}

最終的なまとめ:

1. 価値の移転。-- 値の転送はコンテキストの単なる補助機能であり、一般的に使用されるもの: Cookie、インターセプタまたはログ情報、デバッグ情報レコード

2. タイムアウト制御 - http のタイムアウト設定、rpc 呼び出し、ファイル io やネットワーク io などの時間のかかる操作は、残り時間が十分であるかどうかを確認し、次のステップに進むかどうかを決定できます。

3. キャンセル コントロール - キャンセル信号を送信して、独自のロジックから発生するすべてのゴルーチンが正常にキャンセルされることを確認します。

おすすめ

転載: blog.csdn.net/xia_2017/article/details/128821215