代码结构
我们创建了一个通用的 workerPool 包,根据业务所需的并发性使用 worker 来处理任务。一起来看下目录结构:
workerpool
├── pool.go
├── task.go
└── worker.go
workerpool 目录在项目的根目录下。Task 是需要处理单个工作单元;Worker 是一个简单的 worker 函数,用于执行任务;而 Pool 用于创建、管理 workers。
实现
先看下 Task 代码:
// workerpool/task.go
package workerpool
import (
"fmt"
)
type Task struct {
Err error
Data interface{
}
f func(interface{
}) error
}
func NewTask(f func(interface{
}) error, data interface{
}) *Task {
return &Task{
f: f, Data: data}
}
func process(workerID int, task *Task) {
fmt.Printf("Worker %d processes task %v\n", workerID, task.Data)
task.Err = task.f(task.Data)
}
Task 是一个简单的结构体,保存处理任务所需要的一切数据。创建 task 时,传递了 Data 和待执行函数 f,process() 函数会处理任务。处理任务时,将 Data 作为参数传递给函数 f,并将执行结果保存在 Task.Err 里。
我们来看下 Worker 是如何处理任务的:
// workerpool/worker.go
package workerpool
import (
"fmt"
"sync"
)
// Worker handles all the work
type Worker struct {
ID int
taskChan chan *Task
}
// NewWorker returns new instance of worker
func NewWorker(channel chan *Task, ID int) *Worker {
return &Worker{
ID: ID,
taskChan: channel,
}
}
// Start starts the worker
func (wr *Worker) Start(wg *sync.WaitGroup) {
fmt.Printf("Starting worker %d\n", wr.ID)
wg.Add(1)
go func() {