goroutine 中 panic 仅终止自身,不传播至父 goroutine;须在每个 goroutine 内用 defer+recover 捕获并记录,或改用 channel 返回 error,errgroup 可简化并发错误处理与上下文取消。
Go 的 goroutine 是独立的执行单元,panic 发生后仅终止当前 goroutine,主 goroutine 或其他 goroutine 完全无感。这看似“安全”,实则掩盖错误——比如一个后台日志上传 goroutine 因 http.Post 失败而 panic,程序照常运行,日志却悄然丢失。
常见错误现象:
- 程序无报错、无日志、功能部分失效(如定时任务停摆)
- go run 不输出 panic 信息(因未被捕获且未关联 stdout)
- 使用 recover 却放在错误位置(如放在主函数而非 goro

defer + recover 捕获,不能依赖外部recover() 放在启动 goroutine 的函数里——它只对当前 goroutine 生效log.Printf),否则等于静默丢弃当 goroutine 承担明确任务(如读文件、调 API、处理单条消息),应优先返回 error 而非触发 panic。channel 是最自然的错误传递载体,尤其配合结构体封装结果与错误。
使用场景:
- 启动多个子任务并等待全部完成(如并发请求多个微服务)
- 需区分“任务失败”和“goroutine 崩溃”两类问题
- 要求调用方决定是否重试或降级
type Result struct { Data interface{}; Err error }
ch
select 或循环接收,检查每个 Result.Err
context.Context 本身不传 error,但它让 goroutine 能感知“该停了”,从而主动退出并释放资源。这是对错误响应的前置控制——比如上游请求已超时,下游再继续处理 HTTP 请求就毫无意义。
参数差异:
- context.WithTimeout:指定绝对截止时间,到期自动发 cancel
- context.WithCancel:手动调 cancel() 触发,适合错误连锁响应
- context.WithDeadline:与 timeout 类似,但用具体时间点
context.Context 的 Go 标准库函数(如 http.Do、time.AfterFunc)都会在 context Done 时返回 errorctx.Done() 并及时 return,否则 context 失效golang.org/x/sync/errgroup 是官方维护的扩展包,解决“多个 goroutine 中任意一个出错就整体失败”的典型需求。它内部用 channel + context 封装,比手写更可靠。
性能 / 兼容性影响:
- 无额外 CGO 依赖,纯 Go 实现,可直接 go get
- 启动 goroutine 数量大时(>1000),比手写 channel select 略轻量(复用底层 sync.Pool)
- Go 1.21+ 支持 errgroup.WithContext,自动继承 cancel 行为
import "golang.org/x/sync/errgroup"func fetchAll(urls []string) error { g, ctx := errgroup.WithContext(context.Background()) results := make([]string, len(urls))
for i, url := range urls { i, url := i, url // 避免闭包变量复用 g.Go(func() error { req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) results[i] = string(body) return nil }) } if err := g.Wait(); err != nil { return err // 第一个非 nil error } return nil}
错误真正难处理的地方不在语法,而在权衡:要不要让一个 goroutine 的失败拖垮整个请求?要不要等所有子任务都试一遍再报错?这些决策藏在
errgroup的 “第一个错误就返回” 和自定义 channel 收集全部结果之间,也藏在context.WithTimeout的秒级精度和业务实际容忍度之间。