慣用的なゴルーチンの終了とエラー処理: ケーススタディ
Go では、ゴルーチンの終了の処理は開発者にとってしばしば課題となります。よくある問題の 1 つは、エラーが発生したときにゴルーチンを適切にクリーンアップすることです。この記事では、エラー グループ化を使用した、この問題に対する洗練された慣用的な解決策を示します。
次の例を考えてみましょう。
package main import ( "sync" "time" ) func fetchAll() error { wg := sync.WaitGroup{} errs := make(chan error) // run all the http requests in parallel for i := 0; i < 4; i++ { wg.Add(1) go func(i int) { defer wg.Done() // pretend this does an http request and returns an error time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) errs <- fmt.Errorf("goroutine %d's error returned", i) }(i) } // wait until all the fetches are done and close the error // channel so the loop below terminates go func() { wg.Wait() close(errs) }() // return the first error for err := range errs { if err != nil { return err } } return nil }
この実装には重大な欠陥があります。ゴルーチンがリークします。修正するには、エラー グループを使用します。
package main import ( "context" "fmt" "math/rand" "time" "golang.org/x/sync/errgroup" ) func fetchAll(ctx context.Context) error { errs, ctx := errgroup.WithContext(ctx) // run all the http requests in parallel for i := 0; i < 4; i++ { errs.Go(func() error { // pretend this does an http request and returns an error time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) return fmt.Errorf("error in go routine, bailing") }) } // Wait for completion and return the first error (if any) return errs.Wait() }
エラー グループは、すべての goroutine が正常に完了するまで自動的に待機するか、エラーが発生した場合には残りの goroutine をキャンセルします。上記の場合、エラーが発生した最初のゴルーチンが他のすべてのゴルーチンのキャンセルをトリガーし、エラーが呼び出し元に伝播されます。コンテキストを使用すると、周囲のコンテキストがキャンセルされたときに正常に終了することが保証されます。
以上がGo でゴルーチンを正常に終了し、エラーを処理する方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。