一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して9日目です。クリックしてイベントの詳細をご覧ください。
コルーチンコンテキストに移動context
golangはcontext
主に、キャンセルシグナル、タイムアウト、期限、kvなどのコンテキスト情報をゴルーチン間で転送するために使用されます。
context
golang1.17
バージョン以降に登場した機能です
コンテキスト解決の問題
- コルーチン間の通信
たとえば、Webアプリケーションでは、各要求はコルーチンによって処理されます。もちろん、リクエストを処理するこのコルーチンでは、通常、データベース操作、認証、ファイルの読み取りと書き込みなどの他のサービスを処理するために、他のコルーチンを開始します。これらのコルーチンは独立しており、現在のコルーチンで他のコルーチンがどのように実行されているかを認識できません。ユーティリティチャネルchannel
は通信機能を実現できます
context
context.WithValue()
本質的に、channel
コミュニケーションは
- サブコルーチンのタイムアウト処理
同様に、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)