Go语言任务队列入门:面向初学者
任务队列(task queues)是现代开发中的基础模式之一。在Go(Golang)中,由于内置的并发原语(goroutine和通道),这一机制实现得尤为优雅。本文将从头开始讲解如何在Go中创建任务队列,从简单示例到高级技术。
什么是任务队列,为什么需要它?
任务队列是一种遵循FIFO(First In, First Out——先进先出)原则的数据结构。想象一下排队结账:第一位顾客先被服务,然后是第二位,以此类推。在编程中,这可以实现:
- 将任务的提交与处理分离
- 限制同时执行的操作数量
- 在处理程序之间均匀分配负载
- 在后台处理任务,不阻塞主线程
Go因其并发模型而非常适合实现队列。与许多需要外部库(如RabbitMQ或Redis)的语言不同,在Go中只需几行代码即可创建一个简单的任务队列。
基于Go通道创建简单任务队列
实现任务队列最简单的方法是使用带缓冲的通道。让我们看一个基本示例:
package main
import ( "fmt" "time")
func worker(tasks <-chan string, id int) { for task := range tasks { fmt.Printf("Worker %d 开始任务: %s", id, task) time.Sleep(1 * time.Second) // 模拟工作 fmt.Printf("Worker %d 完成任务: %s", id, task) }}
func main() { tasks := make(chan string, 5) // 缓冲大小为5的通道
// 启动2个worker for i := 1; i <= 2; i++ { go worker(tasks, i) }
// 向队列发送任务 for i := 1; i <= 10; i++ { tasks <- fmt.Sprintf("任务 #%d", i) }
close(tasks) // 发送完所有任务后关闭通道 time.Sleep(2 * time.Second) // 等待完成在这个示例中:
- 通道
tasks充当队列角色 - 两个worker(goroutine)持续监听通道并处理任务
- 大小为5的缓冲区允许在不立即处理的情况下发送最多5个任务
Worker Pool模式:可扩展的处理方式
Worker Pool(工作池)是简单队列的演进。我们不再使用固定数量的worker,而是创建一个可以动态扩展的池。这种模式特别适用于:
- 处理HTTP请求
- 批量数据处理
- 与外部API交互(限制并发请求数量)
以下是使用结构体的更高级实现:
package main
import ( "fmt" "sync" "time")
type Task struct { ID int Payload string}
type WorkerPool struct { tasks chan Task results chan string wg sync.WaitGroup workers int}
func NewWorkerPool(workers int) *WorkerPool { return &WorkerPool{ tasks: make(chan Task, 100), results: make(chan string, 100), workers: workers, }}
func (wp *WorkerPool) Start() { for i := 1; i <= wp.workers; i++ { wp.wg.Add(1) go wp.worker(i) }}
func (wp *WorkerPool) worker(id int) { defer wp.wg.Done() for task := range wp.tasks { result := fmt.Sprintf("Worker %d 执行了任务 %d: %s", id, task.ID, task.Payload) time.Sleep(500 * time.Millisecond) // 模拟工作 wp.results <- result }}
func (wp *WorkerPool) AddTask(task Task) { wp.tasks <- task}\