Golangのコルーチンコンテキスト

一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して9日目です。クリックしてイベントの詳細をご覧ください

コルーチンコンテキストに移動context

golangはcontext主に、キャンセルシグナル、タイムアウト、期限、kvなどのコンテキスト情報をゴルーチン間で転送するために使用されます。

contextgolang1.17バージョン以降に登場した機能です

コンテキスト解決の問題

  1. コルーチン間の通信

たとえば、Webアプリケーションでは、各要求はコルーチンによって処理されます。もちろん、リクエストを処理するこのコルーチンでは、通常、データベース操作、認証、ファイルの読み取りと書き込みなどの他のサービスを処理するために、他のコルーチンを開始します。これらのコルーチンは独立しており、現在のコルーチンで他のコルーチンがどのように実行されているかを認識できません。ユーティリティチャネルchannelは通信機能を実現できます

contextcontext.WithValue()本質的に、channelコミュニケーション

  1. サブコルーチンのタイムアウト処理

同様に、Webアプリケーションでは、メインプロセスは常にメモリに常駐します。各リクエストはコルーチンによって処理されます。処理ビジネスの過程で、他のサービスを処理するために別のコルーチンが開始される場合があります。サブコルーチンが異常またはブロックされている場合、上位レベルのコルーチンに情報をフィードバックすることはできません。メインコルーチンは、フィードバックを受け取らない場合はブロックされます。コンテキストはこの問題を非常にうまく解決contextでき、サブコルーチンまたは子孫コルーチンのタイムアウトまたはタイミング終了を実現できます

コンテキストのいくつかの方法と使用法

context.WithCancel(context.Context)

WithCancel()このメソッドは、直接使用できる空のコンテキストインスタンスを渡しcontext.Background()、コンテキストとキャンセル関数を返します。呼び出しcancal()は他のコルーチンに信号を渡し、サブコルーチンは信号を受信した後に閉じるか処理することができます

package main
​
import (
    "context"
    "fmt"
    "time"
)
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
func main() {
    ctx, cancal := context.WithCancel(context.Background())
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
​
}
​
复制代码

context.WithTimeout(context.Context,timeout)

タイムアウトするコンテキストを定義します。インスタンス化後、カウントダウンが開始されます。時間が来ると、cancel()関数が自動的に呼び出されてサブコルーチンに通知するか、cancel()通知を手動で呼び出すことができます。サブコルーチンにサブコルーチンがある場合は、このコンテキストを引き続き使用します。メインコルーチンがキャンセル信号を送信すると、このコンテキストを使用するすべてのユーザーに通知されます。

package main
​
import (
    "context"
    "fmt"
    "time"
)
​
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
​
func main() {
    ctx, cancal := context.WithTimeout(context.Background(), time.Second*2)
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
​
}
​
复制代码

context.WithDeadline(context.Context,(绝对时间)timeout)

タイムアウトするコンテキストを定義します。Timeout違いは、渡される時間が絶対時間であるということです。指定された時間に達すると、cancel()関数が自動的に呼び出されてサブコルーチンに通知されます。または、cancel()通知を手動で呼び出すこともできます。サブコルーチンにサブコルーチンがある場合は、このコンテキストを引き続き使用します。メインコルーチンがキャンセル信号を送信すると、このコンテキストを使用するすべてのユーザーに通知されます。

package main
​
import (
    "context"
    "fmt"
    "time"
)
​
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
​
func main() {
    ctx, cancal := context.WithDeadline(context.Background(), time.Now().Add(3 * time.Second))
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
​
}
​
复制代码

コルーチン間のコンテキスト通信:context.WithValue()

最初にこのコードを見てください

package main
​
import (
    "context"
    "fmt"
    "time"
)
​
type CTXKEY string
​
func worker(ctx context.Context) {
    // 在子协程中获取上下文信息
    num, ok := ctx.Value(CTXKEY("num")).(string)
    if !ok {
        fmt.Println("invalid trace code")
    }
    fmt.Println(num)
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
​
func main() {
    ctx, cancal := context.WithDeadline(context.Background(), time.Now().Add(3*time.Second))
    // 利用上下文传一个 num = 1234567
    // 实例化一个上下文
    ctx = context.WithValue(ctx, CTXKEY("num"), "1234567")
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
}
​
复制代码

コルーチン間の通信はコンテキストを通じて実現されます。プロジェクトが大規模な場合、変数の汚染を回避するために、原則として、コンテキスト通信に使用されるキーはタイプをカスタマイズする必要があります。

type traceCode string;context.WithValue(context.Context,key,value)

おすすめ

転載: juejin.im/post/7084613288104820773