惯用的 Goroutine 终止和错误处理:案例研究
在 Go 中,处理 Goroutine 终止对于开发人员来说通常是一个挑战。一个常见的问题是确保发生错误时正确清理 goroutine。本文演示了使用错误分组来解决此问题的优雅且惯用的解决方案。
考虑以下示例:
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 }
此实现有一个严重缺陷:它泄漏了 goroutine。修复方法是使用错误组:
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。在上述情况下,遇到错误的第一个 goroutine 会触发所有其他 goroutine 的取消,并将错误传播回调用者。当周围的上下文被取消时,上下文的使用确保了优雅的终止。
以上是如何优雅地终止 Go 中的 Goroutines 并处理错误?的详细内容。更多信息请关注PHP中文网其他相关文章!