goroutine 中的 error 不能直接返回给主 goroutine,必须通过 channel(推荐带缓冲)显式传递,多个 goroutine 写入时可避免阻塞或死锁,panic 可用 recover 捕获后发送至 channel。
Go 的 goroutine 是独立执行的,return 只作用于当前 goroutine,主 goroutine 拿不到它的返回值或 panic。常见错误是写成这样:
go func() {
if err := doSomething(); err != nil {
return // 这里 return 完全没用,主 goroutine 不知道出错了
}
}()
必须显式把 error 传出来——最常用、最可控的方式就是通过 channel。
多个 goroutine 同时写同一个 error channel,如果 channel 无缓冲且没人及时接收,会阻塞甚至死锁。推荐初始化为带缓冲的 channel,容量等于任务数:
errCh := make(chan error, len(tasks)) —— 避免 goroutine 因发送失败卡住recover 捕获并塞进 errCh
for i := 0; i 等待全部结果
不建议用 range 遍历未关闭的 channel,容易提前退出。
不是所有并发错误都要立刻中止。比如批量发 HTTP 请求,你可能想:收集全部错误再统一处理,而不是一个错就放弃其余。
errors.Join(err1, err2, ...)(Go 1.20+)合并多个 error
nil error 后调用 cancel()(配合 context)停止剩余 goroutinenil 不能往 chan error 发,否则接收端无法区分“成功”和“没发”,应只发非 nil 错误,或改用 chan *error
主 goroutine 不能盲目等 N 次 ,万一某个 goroutine 没启动或 panic 在 send 前,就会永久阻塞。稳妥做法是:
sync.WaitGroup 计数,所有 goroutine 结束后 close(errCh),再 range 接收context.WithTimeout 包裹整个流程,超时后主动退出等待真正容易被忽略的是:即使所有任务都成功,也要确保 errCh 被正确关闭,否则 range 永远卡住。