目次
context パッケージについて
context package - context - Go Packages は、Goroutine をキャンセルする API とコンテキスト内で管理しているデータへのアクセスを提供しています。
context パッケージは、並列処理を扱うなかで、done チャネルやデッドラインのパターンを組み込んだイディオムとして Go 1.7 で追加されました。
$ gocloc --not-match=test context
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Go 1 59 254 340
-------------------------------------------------------------------------------
TOTAL 1 59 254 340
-------------------------------------------------------------------------------
使い方と勘所ついては、こちらの書籍がとても分かりやすいです。
Cancel
WithCancel
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
context から context と cancel 関数を返します。 concel を実行することで、Context の Done チャネルが閉じられます。
WithCancel 関数内で、propagateCancel 関数を呼びます。
関数名の通りなのですが、propageteCancel では、親の Context がキャンセルされたときに子の Context をキャンセルさせます。
Context パッケージは、Done チャネルの提供とゴルーチンの親子関係のキャンセルを引き受けています。
WithDeadline
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
withCancel と同様な処理がされますが、指定した時刻を経過したら、cancel を実行し done チャネルを閉じます。
WithTimeout
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
引数に渡した時間経過後、cancel を実行し done チャネルを閉じます。
具体的な実装は、現在時刻に受け取った時間を足し、WithDeadline()を呼び出しています。
WithCancelCause
- func Cause(c Context) error
- func WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)
- type CancelCauseFunc
Go 1.20 で追加されました。withCancel と同様な処理ですが、CancelCause の引数に error を指定し、context がキャンセルされた原因を知ることができます。
Context
空のコンテキストを返します。context.TODO
とcontext.Background
の実態は同じですが、コードに意図を持たせるために使い分けます。
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}
空の context を返します。一時的な実装をする場合などで利用できます。
func hello(ctx context.Context) {
fmt.Println("Hello")
}
func main() {
ctx := context.TODO()
hello(ctx)
}
// Hello
withCancel
, withDeadline
, withTimeout
の詳しい使い方は冒頭で紹介した書籍O’Reilly Japan - Go 言語による並行処理や、よくわかる context の使い方の記事が分かりやすいです。
データアクセス
func WithValue(parent Context, key, val any) Context
コンテキストにキーとデータのペアを含めることができます。
context.Value
メソッドの引数にWithValue
のキーを渡すことでデータを context を通じて利用できます。
type key int
var testKey key
func TestCall(t *testing.T) {
ctx := context.Background()
ctx = context.WithValue(ctx, testKey, "value")
hello(ctx)
}
func hello(ctx context.Context) {
fmt.Println("Hello!")
fmt.Println(ctx.Value(testKey))
}
// value