Goの並行パターン:コンテキスト (Go Concurrency Pattern: Context)
Goの並行パターン:コンテキスト #
Go Concurrency Pattern: Context by Sameer Ajmani
はじめに #
Goで書かれたサーバでは、サーバに来たリクエストはそれぞれそれ自身のゴルーチンで処理されます。 リクエストハンドラはしばしばデータベースやRPCサービスといったバックエンドにアクセスするために追加のゴルーチンを起動します。 リクエストの処理を行っているゴルーチンは、通常エンドユーザのアイデンティティや認可トークン、リクエストの期限などリクエスト固有の値へのアクセス権が必要です。 リクエストがキャンセルされたりタイムアウトした場合には、それらのゴルーチンが使っていたリソースをシステムが再度要求することができるように、そのリクエストの処理を行っているすべてのゴルーチンは素早く終了すべきです。
Googleで私たちは、APIの境界をまたぐリクエスト固有の値やキャンセルのシグナル、期限などを、
あるリクエストの処理に関与するすべてのゴルーチンに投げることを容易にする、 context パッケージというパッケージを開発しました。
パッケージは golang.org/x/net/context に公開されています。 1
この記事ではそのパッケージの使い方と実際に動作する例を紹介したいと思います。
コンテキスト(Context) #
context パッケージの核となっているのは Context 型です。
// ContextはAPIの境界を越えて期限とキャンセルシグナルとリクエスト固有の値を保持します。
// メソッドは複数のゴルーチンから同時に呼び出されても安全です。
type Context interface {
// Doneはこのコンテキストがキャンセルされたりタイムアウトした場合にcloseされます。
Done() <-chan struct{}
// ErrはDoneチャンネルが閉じた後なぜこのコンテキストがキャンセルされたかを知らせます。
Err() error
// Deadlineは設定されている場合にはいつこのContextがキャンセルされるかを返します。
Deadline() (deadline time.Time, ok bool)
// Valueはkeyに紐付いた値を返し、設定がない場合はnilを返します。
Value(key interface{}) interface{}
}
(この説明は要約されたもので、 godoc が正式なものです。)
Done メソッドは、 Context の代わりに動作する関数に対するキャンセルシグナルとして振る舞うチャンネルを返します。チャンネルが閉じられたときに、関数は処理を中断して戻るべきです。
Err メソッドはなぜその Context がキャンセルされたかを示すエラーを返します。
パイプラインとキャンセル の記事では Done チャンネルのイディオムについてより詳細に議論しています。
Context には Done チャンネルが受信専用であるのと同様の理由で Cancel メソッドがあり ません 。
キャンセルシグナルを受け取る関数は通常シグナルを送る関数ではありません。
特に、親の操作が子の操作を行うためのゴルーチンを起動したときに、それらの子の操作が親の操作をキャンセルできるべきではありません。
代わりに WithCancel 関数(あとで説明します)で新しい Context の値をキャンセルする方法を提供します。