

新闻资讯
技术教程goroutine错误无法直接返回主函数,需用errgroup.Group、channel+WaitGroup或context控制;errgroup默认返回首个错误,全量收集需自定义channel;超时须配合context避免阻塞。
Go 的 goroutine 是独立执行的,一旦启动就脱离调用栈,return 值或 panic 都不会传回主 goroutine。常见错误是写成这样:
func doWork() error {
go func() {
// 模拟失败
panic("failed in goroutine")
}()
return nil // 主函数收不到 panic,也收不到子 goroutine 的 error
}这会导致错误被静默吞掉。必须显式传递错误——用 channel、sync.WaitGroup 配合 error 类型变量,或用 errgroup.Group。
errgroup.Group 是 Go 官方 golang.org/x/sync/errgroup 提供的工具,能自动等待所有 goroutine 结束,并返回第一个非 nil 错误(或 nil 表示全部成功)。
sync.WaitGroup 和带缓冲的 error channeleg.Go(ctx, fn) 会在 ctx 取消时自动中止未启动的任务chan error
import "golang.org/x/sync/errgroup"func processAll(urls []string) error { var eg errgroup.Group for , url := range urls { url := url // 避免循环变量复用 eg.Go(func() error { , err := http.Get(url) return err }) } return eg.Wait() // 阻塞直到全部完成,返回首个 error }
当需要保留所有错误(比如做批量操作审计),就不能依赖 errgroup 的“首个错误”语义,得自己建 chan error 并控制容量。
make(chan error, len(tasks))),否则发送会阻塞WaitGroup 的 Done() 要在 defer 里调用,确保即使 panic 也执行func runWithAllErrors(tasks []func() error) []error {
var wg sync.WaitGroup
errs := make(chan error, len(tasks))
for _, task := range tasks {
wg.Add(1)
go func(t func() error) {
defer wg.Done()
if r := recover(); r != nil {
errs <- fmt.Errorf("panic: %v", r)
return
}
if err := t(); err != nil {
errs <- err
}
}(task)
}
wg.Wait()
close(errs)
var result []error
for err := range errs {
result = append(result, err)
}
return result}
context.WithTimeout 配合错误收集防无限等待
并发任务若不设超时,一个卡死的 goroutine 会让 WaitGroup.Wait() 或 errgroup.Wait() 永远阻塞。必须结合 context 控制生命周期。
errgroup.Group 的 Go 方法支持传入 context.C
ontext,任务函数可监听 ctx.Done()
ctx.Done(),及时退出ctx.Err() 是 context.DeadlineExceeded,应作为错误之一返回容易忽略的是:超时 context 取消后,正在运行的 goroutine 不会自动停止,必须主动检查 ctx.Err() == nil 才继续执行关键逻辑。