并发模式:工作池与 errgroup
原语(goroutine、channel、锁)解决"怎么通信与同步",模式解决"如何组织"才能既高效又可控。本节介绍两个最常用的生产模式:worker pool 与 errgroup。
Worker Pool:固定大小工作池
无限制地 go func() 会在任务量大时耗尽内存或打垮下游。工作池模式预先启动固定数量的 worker,从任务通道持续取任务,实现并发度上限与背压:
要点:
jobs通道由投递方关闭,worker 通过for range感知退出。results由独立的收尾 goroutine 在wg.Wait()后关闭,主流程用for range安全收集。- 并发度 = worker 数量;任务缓冲用于平滑投递高峰。
Tip
worker 数量的经验值:CPU 密集型任务取 runtime.NumCPU();I/O 密集型(HTTP 调用、数据库访问)取决于下游承受能力,通常配额 10–100 并通过压测确定。
errgroup:带错误传播与限流的并发
批量并发任务中,任一子任务失败往往应当整体取消。golang.org/x/sync/errgroup 将 WaitGroup、错误收集与 context 取消打包:
errgroup 的三项核心能力:
SetLimit:有界并发的批量处理
Go 1.22+ 中循环变量已按迭代隔离,item := item 的复制写法不再必要,保留仅为兼容旧版本。
模式选型
:::warning 两条共性陷阱:
- 不要在循环里无限
go:任务量不可控时一律使用池或SetLimit。 - 通道关闭权与发送方绑定:无论哪种模式,只由发送方关闭通道,避免向已关闭通道发送导致 panic。 :::
小结
- worker pool 以固定 goroutine 数消费任务通道,提供并发上限与背压。
- errgroup 合并等待、错误传播与 context 取消,
SetLimit提供内置限流。 - 两者可组合:用 errgroup 管理 worker 生命周期是常见的工程化封装。