0Pricing
Go Academy · 课时

工作池模式

限制并发量

工作池模式 是 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 工作池模式
  2. 扇出与扇入
  3. 处理流程阶段
  4. 优雅关闭
← 返回 Go Academy