📑
go文を使わずにctx.Done()で中断させる
小ネタなのですがループ処理が行われている最中にctx.Done()
になったら、 その処理を終了させるという場面があります。
サンプルコードでこういう感じのを見かける気がします(主観)。私もこんな雰囲気のものを書いたことがありました。
func ctxLoop(ctx context.Context) []string {
out := make(chan string,100)
go func() {
defer close(out)
for i := 0; i < 100; i++ {
res := getDataFromServer()
out <- res
}
}()
var result []string
for {
select {
case <-ctx.Done():
return result
case res, ok := <-out:
if !ok {
return result
}
result = append(result, res)
}
}
}
しかしあるとき気がついたのですが、こう書いてしまえば非常にシンプルになります。
func ctxLoopSimple(ctx context.Context) []string {
var result []string
for i := 0; i < 100; i++ {
select {
case <-ctx.Done():
return result
default:
}
res := getDataFromServer()
result = append(result, res)
}
return result
}
chanelのハンドリングはしているのですが、実はgo文すら必要ありませんでした。
ポイントは以下の部分ですね。 ctx.Done()
でなければ default
で進行します。goroutineの無いところでもイディオム的に使っていけます。
select {
case <-ctx.Done():
return result
default:
}
go文がなくなってコードの複雑度も下がり、バグが予防できますし、簡単です。ご参考に。
Discussion