Golang 怎么实现一个简单的协程池?

2次阅读

协程池用于控制并发安全:每个goroutine至少占2KB空间,无节制启动易致内存耗尽或压垮下游;通过固定worker数量限制并发上限,并用chan实现任务队列与复用。

Golang 怎么实现一个简单的协程池?

为什么不能直接用 go func() 而要搞协程池?

因为无节制地起 go func() 容易耗尽内存或压垮下游服务:每个 goroutine 至少占 2KB 空间,上万并发时就是几十 MB;更关键的是,如果任务本身有 IO 或依赖外部资源(比如数据库连接、http 客户端),不加限制会导致连接打满、超时激增、错误率飙升。

协程池本质是「限制并发数 + 复用 goroutine」,不是为了减少 goroutine 数量,而是控制它在安全水位内运行。

worker 模型怎么搭?用 chan 做任务队列最轻量

核心结构就三样:jobs 输入通道(接收任务)、固定数量的 worker goroutine(从 jobs 取任务执行)、done 通道(通知任务完成)。不需要第三方库,标准库足矣。

  • jobs 设为带缓冲通道(比如 make(chan func(), 1000)),避免提交任务时阻塞调用方
  • 启动 N 个 worker:每个都跑一个 for job := range jobs { job() } 循环
  • 任务函数类型统一为 func(),简单场景够用;需要传参就用闭包封装,比如 func() { doWork(x, y) }
  • 别忘了关 jobs 通道来退出所有 worker——但通常池子长期运行,这步可延后

怎么控制最大并发数?靠启动时固定的 worker 数量

并发上限 = 启动的 worker 数量,和 jobs 缓冲区大小无关。后者只影响「任务能攒多少」,前者才决定「同一时刻最多几个在跑」。

立即学习go语言免费学习笔记(深入)”;

示例代码片段:

type Pool struct { jobs chan func() } 

func NewPool(maxWorkers int) *Pool { p := &Pool{ jobs: make(chan func(), 1000), // 缓冲区只是防提交卡住 } for i := 0; i < maxWorkers; i++ { go func() { for job := range p.jobs { job() } }() } return p }

func (p *Pool) Submit(job func()) { p.jobs <- job>

实际用的时候最容易漏哪几件事?

不是写完 Submit 就完事了。真实场景下这几个点常被跳过:

  • 任务 panic 会导致 worker 退出,整个池子悄悄少一个并发能力——必须在 job() 外层加 recover
  • 没有任务超时控制:某个 job 卡死(比如 HTTP 请求没设 timeout),会一直占着这个 worker
  • 池子没提供等待全部任务完成的机制,比如想等所有 Submit 的任务跑完再 exit,得自己加 sync.WaitGroupdone 通道
  • 忘记限制 jobs 缓冲区大小,导致 OOM:100 万任务全塞进去,每个闭包哪怕只捕获几个 int,内存也扛不住

真正稳的协程池,90% 的代码都在处理这些边界,而不是调度逻辑本身。

text=ZqhQzanResources