Go 技巧:使用带缓冲的通道实现高效工作池
Go 语言的并发模型是其最大亮点之一,而通道(channel)则是 goroutine 之间通信的核心。今天分享一个实用技巧:使用带缓冲的通道实现工作池,有效控制并发数量,防止资源耗尽。
传统方式的痛点
初学者常直接用 go func() 启动任务,但当任务量巨大时,会创建大量 goroutine,导致调度压力和内存暴涨。
缓冲通道实现工作池
func workerPool(tasks []Task, workerNum int) []Result {
taskCh := make(chan Task, len(tasks))
resultCh := make(chan Result, len(tasks))
// 启动 worker
for i := 0; i < workerNum; i++ {
go func() {
for task := range taskCh {
resultCh <- process(task)
}
}()
}
// 发送任务
for _, task := range tasks {
taskCh <- task
}
close(taskCh)
// 收集结果
results := make([]Result, 0, len(tasks))
for i := 0; i < len(tasks); i++ {
results = append(results, <-resultCh)
}
return results
}
关键点解析
- 缓冲通道:
taskCh的缓冲大小等于任务数,避免发送者阻塞 - worker 数量可控:通过
workerNum精确控制并发 goroutine 数量 - 任务分发:多个 worker 从同一个通道竞争读取,自动负载均衡
- 结果收集:使用另一个通道收集处理结果
使用示例
tasks := generateTasks(1000)
results := workerPool(tasks, 10) // 10 个 worker 处理 1000 个任务
这种模式在实际项目中广泛使用,如批量数据处理、API 请求限流等场景。通过调整 worker 数量,可以找到性能和资源消耗的最佳平衡点。
小贴士:worker 数量通常设置为 CPU 核心数的 2-4 倍,但具体需结合任务类型(CPU 密集型还是 IO 密集型)进行基准测试确定。