工作池模式
限制并发量
工作池模式 是 CoddyKit 上的免费 Go Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。
什么是 worker 池
worker 池会启动固定数量的协程,让它们都从共享通道中获取任务。与其为每个任务启动一个协程,不如启动 N 个 worker 并向它们提供工作。
- 限制并发操作的数量
- 复用协程,而不是创建成千上万个协程
- 保护数据库或应用程序接口等共享资源
为什么要限制并发
不受限制的协程可能耗尽内存和文件描述符,或使下游服务不堪重负。工作池可以让您控制同时运行的工作量。
如果您有 10000 个网址需要获取,就不应同时发起 10000 个 HTTP 请求。使用包含 20 个 worker 的池可以将并发量控制在合理范围内。
jobs 通道
任务会流入 jobs 通道。每个 worker 在 for range 循环中从该通道读取任务。当通道关闭时,循环结束,worker 退出。
jobs := make(chan int, 100)
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)单个 worker
worker 只是一个遍历 jobs 通道的函数。它处理每个任务,并将结果写入 results 通道。
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}启动多个 worker
使用一个简单的循环启动工作池。每次循环都会启动一个运行同一 worker 函数的协程。它们共享同一个 jobs 通道和 results 通道。
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}单向通道类型
请注意 worker 签名中的 <-chan int(只读)和 chan<- int(只写)。这些单向类型让编译器能够阻止 worker 意外向 jobs 发送数据或从 results 读取数据。
收集结果
提交所有任务并关闭通道后,main 协程会读取与任务数量完全相同的结果数。这样可以同步程序,避免程序过早退出。
sum := 0
for a := 1; a <= 5; a++ {
sum += <-results
}
fmt.Println("total:", sum)完整的可运行工作池
下面是在一个程序中实现的完整模式:三个 worker 将五个数字分别乘以二。运行程序并观察总结果。
package main
import "fmt"
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}
func main() {
jobs := make(chan int, 5)
results := make(chan int, 5)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
total := 0
for a := 1; a <= 5; a++ {
total += <-results
}
fmt.Println("total:", total)
}有缓冲与无缓冲
有缓冲的 jobs 通道允许生产者将工作排队,直到缓冲区填满前都不会阻塞。无缓冲通道则强制进行交接:发送操作会一直阻塞,直到有 worker 准备接收。缓冲可以平滑工作量突发的生产者。
选择工作池大小
对于 CPU 密集型工作,可以将工作池大小设置为接近 runtime.NumCPU()。对于 IO 密集型工作(网络、磁盘),可以设置得大得多,因为 worker 花费时间等待,而不是进行计算。
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("CPUs:", runtime.NumCPU())
}避免协程泄漏
如果忘记 close(jobs),worker 会在空通道上永久阻塞并发生泄漏。提交完所有工作后,务必关闭 jobs 通道,使 for range 循环终止。
快速检查
请测试您对 worker 池的理解。
回顾
您已学会 worker 池模式:
- 启动固定数量的 worker,从共享的作业通道读取
- 使用单向通道类型来提高安全性
- 关闭作业通道以终止 worker
- 收集结果以同步完成状态
- 根据工作负载类型(CPU 与 IO)设置池大小
常见问题解答
「工作池模式」课时是免费的吗?
是的 — 「工作池模式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。
「工作池模式」这节课中我会学到什么?
限制并发量 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Go Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「工作池模式」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Go Academy 课中编写并运行代码吗?
能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。