`errgroup`でGoにおける同時実行タスクの管理
James Reed
Infrastructure Engineer · Leapcell

Key Takeaways
errgroup
は、エラー処理とコンテキストキャンセルにより、同時実行のゴルーチンの管理を簡素化します。WithContext
を使用すると、失敗時にすべてのゴルーチンを早期に終了できます。SetLimit
は、アクティブな同時実行ゴルーチンの数を制御して、リソースの使用率を最適化します。
Goのerrgroup
パッケージは、共通タスクのサブタスクで動作するゴルーチンのグループに対して、同期、エラー伝播、およびコンテキストキャンセルを提供します。これはgolang.org/x/sync
モジュールの一部であり、エラーを返す可能性のある同時実行操作を管理する便利な方法を提供します。
errgroup
の概要
errgroup
パッケージは、関連するタスクを実行する複数のゴルーチンの管理を簡素化するように設計されています。エラー処理およびコンテキストキャンセル機能を追加して、sync.WaitGroup
の機能を拡張します。これは、いずれかのゴルーチンがエラーを検出した場合、グループ全体をキャンセルでき、エラーを呼び出し元に伝播できることを意味します。
主要なコンポーネント
errgroup
パッケージの主要なコンポーネントは次のとおりです。
- Group: 同じ全体的なタスクのサブタスクで動作するゴルーチンのコレクション。
- WithContext: 新しい
Group
と、指定されたコンテキストから派生した関連するContext
を作成します。 - Go: 新しいゴルーチンで実行される関数を登録します。
- Wait: 登録されているすべての関数が完了するまで待機し、最初に見つかったnilでないエラーを返します(存在する場合)。
基本的な使用法
errgroup
を使用して複数のURLを同時にフェッチする方法の例を次に示します。
package main import ( "fmt" "net/http" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group var urls = []string{ "http://www.golang.org/", "http://www.google.com/", "http://www.somestupidname.com/", } for _, url := range urls { url := url // クロージャの問題を回避するために新しい変数を作成します g.Go(func() error { resp, err := http.Get(url) if err == nil { resp.Body.Close() } return err }) } if err := g.Wait(); err == nil { fmt.Println("Successfully fetched all URLs.") } else { fmt.Printf("Failed to fetch URLs: %v\n", err) } }
この例では、errgroup.Group
が作成され、URLごとに、HTTP GETリクエストを実行するために新しいゴルーチンが起動されます。g.Go
メソッドは、同時に実行される関数を登録します。g.Wait
メソッドは、すべてのゴルーチンが完了するまで待機し、最初に見つかったエラーを返します(存在する場合)。
コンテキストを使用したerrgroup
の使用
WithContext
関数を使用すると、コンテキストキャンセルが可能になり、いずれかのゴルーチンがエラーを検出した場合に、すべてのゴルーチンをキャンセルできます。これは、タスクが相互に依存している場合、または失敗時に早期終了が必要な場合に特に役立ちます。
package main import ( "context" "fmt" "golang.org/x/sync/errgroup" "time" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() g, ctx := errgroup.WithContext(ctx) for i := 0; i < 3; i++ { i := i // Closureキャプチャを避ける g.Go(func() error { if i == 1 { return fmt.Errorf("error in goroutine %d", i) } select { case <-time.After(2 * time.Second): fmt.Printf("goroutine %d completed\n", i) case <-ctx.Done(): fmt.Printf("goroutine %d canceled\n", i) } return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Group finished with error: %v\n", err) } else { fmt.Println("Group finished successfully") } }
このコードでは、いずれかのゴルーチンがエラーを返すと、コンテキストがキャンセルされ、他のゴルーチンがコンテキストのキャンセルを尊重する場合、早期に終了します。
SetLimit
を使用した同時実行の制御
SetLimit
メソッドを使用すると、任意の時点でアクティブなゴルーチンの最大数を制御できます。これは、大量のタスクを処理する場合にリソースの使用量を制限するのに役立ちます。
package main import ( "fmt" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group g.SetLimit(2) // 同時実行ゴルーチンを2つに制限します for i := 0; i < 5; i++ { i := i // Closureキャプチャを避ける g.Go(func() error { fmt.Printf("Starting task %d\n", i) // 作業をシミュレートします return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Group finished with error: %v\n", err) } else { fmt.Println("Group finished successfully") } }
ここでは、SetLimit(2)
により、同時にアクティブになるゴルーチンは2つ以下になります。新しいゴルーチンは、アクティブなゴルーチンが完了するまで待機してから開始します。
よくある落とし穴
errgroup
を使用する場合、次の点に注意してください。
-
Closureでの変数のキャプチャ: ループ変数がClosureで正しくキャプチャされ、予期しない動作を回避するようにします。これは通常、ループ内に新しい変数を作成することによって行われます。
-
コンテキストのキャンセル:
WithContext
を使用する場合、ゴルーチンはctx.Done()
をチェックして、キャンセル時に速やかに終了することにより、コンテキストのキャンセルを尊重する必要があります。 -
エラー処理:
errgroup
は、最初に見つかったnilでないエラーのみをキャプチャします。すべてのエラーを収集する必要がある場合は、追加のエラー集約ロジックを実装する必要があります。
errgroup
パッケージを活用することで、Go開発者は、組み込みのエラー処理とコンテキスト認識のキャンセルにより、複雑な同時実行ワークフローをより効果的に管理できます。
FAQs
errgroup
はエラーを伝播し、コンテキストキャンセルをサポートしますが、sync.WaitGroup
はゴルーチンの完了を待機するだけです。
最初のエラーが返され、WithContext
を使用している場合は、他のゴルーチンがキャンセル信号を受信します。
SetLimit(n)
を使用して、n
個のゴルーチンのみが同時に実行されるようにします。
Leapcellは、Goプロジェクトをホストするための最高の選択肢です。
Leapcellは、Webホスティング、非同期タスク、およびRedisの次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、またはRustで開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い — リクエストも料金も発生しません。
比類のないコスト効率
- アイドル料金なしの従量課金制。
- 例:25ドルで、平均応答時間60ミリ秒で694万件のリクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOpsの統合。
- 実用的な洞察を得るためのリアルタイムメトリックとロギング。
簡単なスケーラビリティと高いパフォーマンス
- 高い同時実行性を容易に処理するための自動スケーリング。
- 運用上のオーバーヘッドはゼロ — 構築に集中するだけです。
ドキュメントで詳細をご覧ください!
Xでフォローしてください:@LeapcellHQ