並行エラー処理のためのerrgroup
golang.org/x/sync/errgroupを実際に使います。
「並行エラー処理のためのerrgroup」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
goroutineとエラーの問題
go func()でgoroutineを起動すると、エラーを含む戻り値が破棄されます。エラーを収集するには、チャネルやWaitGroupなどの追加の仕組みが必要です。errgroupを使うと簡単になります。
golang.org/x/sync/errgroup
errgroup.Groupはgoroutineを実行し、エラーを収集します。Wait()はすべてのgoroutineが終了するまでブロックし、nilでない最初のエラーを返します。
var g errgroup.Group
g.Go(func() error { return fetchUsers() })
g.Go(func() error { return fetchOrders() })
if err := g.Wait(); err != nil {
log.Fatal(err)
}errgroup.WithContext
WithContextは、グループと派生したcontextを返します。最初のgoroutineがエラーを返すとcontextがキャンセルされ、残りの処理が停止します。
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error { return doWork(ctx) })
g.Go(func() error { return doOtherWork(ctx) })
err := g.Wait()エラーとともに結果を収集する
errgroupが収集するのはエラーだけで、結果は収集しません。同期処理を避けるため、あらかじめ確保したスライスにインデックスを使って結果を格納します。
results := make([]Result, len(items))
for i, item := range items {
i, item := i, item
g.Go(func() error {
r, err := process(ctx, item)
if err != nil { return err }
results[i] = r
return nil
})
}
if err := g.Wait(); err != nil { return err }g.SetLimit(Go 1.20以降)
g.SetLimit(n)は、同時に実行されるgoroutineの数に上限を設定します。別のチャネルを使わずにセマフォとして機能します。
g.SetLimit(10) // at most 10 goroutines at once
for _, item := range items {
g.Go(func() error { return process(item) })
}g.TryGo
g.TryGo(f)は、SetLimitで設定した上限に余裕がある場合にのみgoroutineを起動します。起動しなかった場合はfalseを返します。
返されるのは最初のエラーだけ
errgroupが返すのは最初のエラーだけです。すべてのエラーが必要な場合は、各goroutine内でミューテックスにより保護したスライスに収集してください。
var mu sync.Mutex
var errs []error
g.Go(func() error {
if err := doWork(); err != nil {
mu.Lock(); errs = append(errs, err); mu.Unlock()
}
return nil
})sync.WaitGroupとの違い
WaitGroupは完了を追跡します。一方、errgroupは完了を追跡し、さらにエラーを収集します。いずれかのgoroutineの失敗を報告する必要がある場合は、errgroupを優先してください。
contextのキャンセル伝播
errgroup.WithContextを使用すると、派生したcontextのキャンセル通知によって、ほかのすべてのgoroutineに停止を指示できます。これは、最初のエラーでキャンセルする仕組みと似ています。
errgroupコードのテスト
テストでは、WithTimeoutを使ってcontextを注入し、goroutineが停止しない場合でもグループが永久に実行され続けないようにしてください。
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
g, ctx := errgroup.WithContext(ctx)セマフォの代替手段
SetLimitが導入される前(Go < 1.20)は、個々のgoroutine内でバッファ付きチャネルをセマフォとして使用すると、同じ効果を得られます。
クイックチェック
errgroup.WithContextは、通常のerrgroup.Groupにはない何を返しますか。
まとめ:errgroup
重要なポイント:
- g.Go(func() error):起動し、最初のエラーを収集します
- g.Wait():すべての処理が完了するまでブロックし、最初のエラーを返します
- WithContext:最初のエラーでcontextをキャンセルします
- g.SetLimit(n):同時実行するgoroutine数に上限を設定します(Go 1.20以降)
よくある質問
「並行エラー処理のためのerrgroup」レッスンは無料ですか?
はい。「並行エラー処理のためのerrgroup」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「並行エラー処理のためのerrgroup」で何を学びますか?
golang.org/x/sync/errgroupを実際に使います。 ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「並行エラー処理のためのerrgroup」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- パイプラインとステージのパターン
- 並行エラー処理のためのerrgroup
- セマフォパターン
- リーク検出とキャンセル