回顾:工作池
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 66 课,共 107 课。
挑战
简单让我们使用工作池模式来构建一个任务处理系统!你将创建一个工作池,让多个工作线程并发处理计算任务,展示通道、goroutine 和 WaitGroup 如何协同工作,高效处理工作负载。
你需要将代码分为两个文件:
pool.go:定义工作池组件及其逻辑。创建一个
Task结构体,包含表示待处理工作的ID(int)和Value(int)字段。创建一个
Result结构体,包含表示已完成工作的TaskID(int)和Computed(int)字段。实现一个
Worker函数,接收工作线程 ID(int)、仅接收任务的通道(<-chan Task)、仅发送结果的通道(chan<- Result)以及一个指向sync.WaitGroup的指针。每个工作线程都应:- 使用
defer wg.Done()发出完成信号 - 遍历任务通道,处理每个任务
- 对每个任务,计算其 Value 的平方
- 发送包含 TaskID 和计算所得平方的 Result
实现一个
RunPool函数,接收工作线程数量(int)和任务切片。此函数应:- 创建用于任务和结果的带缓冲通道(使用任务数量作为缓冲区大小)
- 以 goroutine 的形式启动指定数量的工作线程
- 将所有任务发送到任务通道,然后关闭该通道
- 使用带有 WaitGroup 的 goroutine,在所有工作线程完成后关闭结果通道
- 将所有结果收集到切片中并返回
- 使用
main.go:读取输入并协调工作池。先读取工作线程数量,再读取任务数量。对于每个任务,读取其 ID 和值。使用工作线程和任务调用
RunPool,然后按以下格式打印每个结果:Task [TaskID]: [Computed]按 TaskID 升序排列结果后再打印。
输入格式如下:
- 第 1 行:工作线程数量(整数)
- 第 2 行:任务数量(整数)
- 后续行:每个任务占两行,分别为任务 ID(整数)和任务值(整数)
例如,给定:
2
4
1
3
2
5
3
2
4
7输出应为:
Task 1: 9
Task 2: 25
Task 3: 4
Task 4: 49工作线程会并发处理任务(3 的平方是 9,5 的平方是 25,依此类推),然后按任务 ID 的顺序收集并显示结果。2 个工作线程处理 4 个任务时,工作会在工作池中得到高效分配。
亲手试试
package main
import (
"fmt"
"sort"
)
func main() {
// 读取工作线程数量
var numWorkers int
fmt.Scanln(&numWorkers)
// 读取任务数量
var numTasks int
fmt.Scanln(&numTasks)
// 读取任务
tasks := make([]Task, numTasks)
for i := 0; i < numTasks; i++ {
var id, value int
fmt.Scanln(&id)
fmt.Scanln(&value)
tasks[i] = Task{ID: id, Value: value}
}
// TODO: 用工作线程和任务调用 RunPool
// TODO: 按 TaskID 升序排列结果
// TODO: 按以下格式输出每个结果:Task [TaskID]: [Computed]
}
面向对象编程中的所有课
自己练习: Go 在线编译器