Go 言語のコンテキストは非常に使いやすく、ほとんどすべての Go プログラムがリクエスト範囲の値を渡すためにこれを使用します。これは、キャンセルシグナル、期限、リクエスト ID などを含む、リクエストスコープの値を API 境界を越えて渡すことを可能にする軽量のオブジェクトです。
この記事では、Go Context の使用法を詳しく調べ、その利点と、それを使用してアプリケーションのパフォーマンスと堅牢性を向上させる方法を理解します。
Go コンテキストとは何ですか?
Go Context は Go 言語の標準ライブラリであり、リクエスト範囲値を管理するために使用されます。これは、ゴルーチン間で要求された変数を渡すための軽量かつ推移的なメソッドをアプリケーションに提供します。これは主に、キャンセルリクエスト、タイムアウト制限、追跡ログ、リクエストコンテキスト、リクエストデータなどを渡すために使用されます。
他のプログラミング言語の Context とは異なり、Go Context には非常に特別なプロパティがいくつかあります。
使用シナリオ
Go Context は、さまざまなシナリオでアプリケーションに使用できる非常に汎用性の高いツールです。たとえば、次のようなシナリオがあります。
Web アプリケーションは、最も一般的な使用シナリオの 1 つです。 HTTP リクエストの処理に必要なコンテキストとリクエスト固有のメタデータを簡単に管理できます。 HTTP リクエストの処理中に、コンテキストはリクエスト ID、リクエストのタイムアウト、キャンセル信号などをハンドラ間で渡すために使用されます。たとえば、コンテキストは、Websocket 接続を処理するときにセッション状態を追跡するために使用されます。
バックグラウンド サービス アプリケーションは、外部システムにデータを提供するために複数の API を横断する必要がある場合があります。そのようなアプリケーションでは、ゴルーチンを完了するためにコンテキストが使用されます。より効率的な終了、この種のアプリケーションに最適です。これを実現するには、Context WithCancel 標準関数を使用します。すべてのゴルーチンがこのコンテキストを使用する場合、すべてのサブスクリプションを停止してリソースをクリーンアップするために必要なコールバックは 1 つだけです。
Go Context は、大規模なファイルおよび DB 操作を処理するための理想的なツールです。これらの操作はリソースと I/O を大量に消費する可能性があるためです。この場合、コンテキストを使用して操作をキャンセルし、間違いや実行時エラーを回避します。
マイクロサービス アーキテクチャでは、リクエスト スコープの情報を API から各サービスの呼び出しチェーンに渡すために、コンテキストが広く使用されています。この場合、トレース ID はコンテキストに保存され、複数のサービスに接続するときに渡されます。これにより、リクエスト行全体のトレースが簡単になります。
コンテキストの使用法
Go Context の基本を理解したところで、それを使用してリクエスト スコープの値を管理する方法を検討します。
Go 言語では、context.Background() を使用して空のトップレベル コンテキストを作成できます。このコンテキストはグローバルに独立しており、値は含まれません。
ctx := context.Background()
WithValue() 関数を使用して、値を含むコンテキストを作成することもできます。たとえば、リクエスト データとタイムアウト制限を使用して HTTP リクエスト処理コンテキストを作成できます。
ctx := context.WithValue( context.Background(), "requestId", uuid.New())
ctx.Value() 関数は、このコンテキストを使用してコンテキストの値を取得します。以下の例では、一意の識別子をリクエストすることでコンテキスト情報を取得できます。
requestId, ok := ctx.Value("requestId").(value string)
context.WithDeadline 関数または context.WithTimeout 関数を使用すると、長時間実行プロセスを回避するためにコンテキストにタイムアウト信号を適用することもできます。
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel()
cancel() 関数は、コンテキストのキャンセル ステータスをマークするために使用されます。タイムアウト イベントが発生すると、コンテキストは自動的にキャンセルされます。
select { case <-timeOutCtx.Done(): if err := timeOutCtx.Err(); err != nil { fmt.Println("Time out due to: ", err) } case <-time.After(5 * time.Second): fmt.Println("Hooray! Request done within 5 sec") }
この例では、10 秒のタイムアウト コンテキストを作成します。 select ステートメントは 2 つのチャネルでの操作を待機します。 Done() メソッドは、Context がキャンセルされるかタイムアウトになるとシグナルを発行します。
タイマー チャネルを通じて短いメッセージを送信し、5 秒間待ちます。 context.WithTimeout() 関数の 2 番目の引数は 10 秒であるため、select ステートメントの最初のルートのみを実行する必要があります。
コンテキスト 長時間実行プロセス中に使用されるキャンセル信号の機能を使用して、システムへの予期せぬ負荷を回避できます。
次のコード スニペットでは、context.WithCancel() を使用してコンテキストを作成し、cancel() 関数を使用してコンテキストのキャンセル ステータスをマークします。 Context がキャンセルされる前に指定された goroutine が完了した場合、その完了シグナルは Done() メソッド経由で送信されます。
ctx, cancel := context.WithCancel(context.Background()) go func(ctx context.Context) { select { case <-ctx.Done(): fmt.Println("Exiting goroutine") return default: fmt.Println("Processing...") } }(ctx) // Exit after 5 sec time.AfterFunc(5*time.Second, cancel)
ここでは、Done() と goroutine のデフォルトのブランチを使用します。 Context がキャンセルされるかタイムアウトになると、Done() メソッドはシグナルを返し、cancel() 関数を呼び出してゴルーチンの実行をキャンセルします。
main 関数では、time.AfterFunc() 関数を使用してこのコンテキストの cancel() 関数を呼び出し、コンテキストのキャンセル ステータスをマークします。これにより、5 秒後に goroutine のキャンセルがトリガーされます。
在处理请求的时间,我们通常需要确保 goroutine 不会无限期地等待,而需要在可接受的时间范围内执行操作。
在下面的代码段中,我们将使用 context.WithTimeout() 函数创建一个带有 5 秒超时限制的 Context。
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() select { case <-time.After(5 * time.Second): fmt.Println("Request completed") case <-ctx.Done(): fmt.Println("Exit due to: ", ctx.Err()) }
我们也使用了 cancel() 函数,确保 Context 被取消时自动触发。
为了模拟一个长时间的操作,我们使用 time.After(channel)。 当 goroutine 执行时间超过 2 秒时,Context 始终会被取消。 select 语句通过检查两个 channel 的操作结果而“安全地”退出。
总结
在 Go 语言中,Context 是通用工具,用于管理请求范围的数据。它提供了一种非常强大,灵活的方法,以跨 API 边界传递请求范围的值,如取消信号、截止日期、请求 ID 等。
在本文中,我们深入探讨了 Go Context 的一些实际用例,并讨论了一些最佳实践,以优化应用程序的可维护性和性能。
随着应用程序和网络的规模增长,Context 的正确使用和管理变得非常重要。如果用得当,它可以提高应用程序的健壮性和性能,从而确保进行细粒度的请求管理。
以上がGo Context の使用法について詳しくは、こちらをご覧ください。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。