Menu
CoddyTech

回顾:工作池

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 66 课,共 107 课。

challenge icon

挑战

简单

让我们使用工作池模式来构建一个任务处理系统!你将创建一个工作池,让多个工作线程并发处理计算任务,展示通道、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 在线编译器