整体设计思路
- 任务接口定义:定义一个接口
Task
,包含 Execute
方法,所有具体任务结构体都实现这个接口。
- 任务提交:创建一个任务队列(如
channel
),用于接收提交的任务。
- 任务调度:使用多个工作协程从任务队列中取出任务并执行。
- 资源管理与并发控制:利用
sync.Mutex
或 sync.RWMutex
来控制对共享资源的访问,防止资源竞争。
关键部分代码实现
package main
import (
"fmt"
"sync"
)
// 定义任务接口
type Task interface {
Execute()
}
// 具体任务结构体
type ExampleTask struct {
id int
}
func (t *ExampleTask) Execute() {
fmt.Printf("Task %d is executing\n", t.id)
}
func main() {
var wg sync.WaitGroup
taskQueue := make(chan Task, 100)
const numWorkers = 5
// 启动工作协程
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for task := range taskQueue {
task.Execute()
}
}()
}
// 提交任务
for i := 0; i < 20; i++ {
task := &ExampleTask{id: i}
taskQueue <- task
}
close(taskQueue)
wg.Wait()
}
性能瓶颈分析
- 任务队列长度限制:如果任务提交速度过快,任务队列可能会满,导致提交任务的协程阻塞。
- 资源竞争:虽然使用了锁来控制资源访问,但频繁的加锁解锁操作会带来性能开销。
- 工作协程数量:工作协程数量如果设置不当,可能导致 CPU 利用率不足或过度竞争。
优化方向
- 动态任务队列:可以使用无缓冲的
channel
结合 select
语句实现动态的任务队列,避免固定长度队列的限制。
- 减少锁的使用:采用读写分离的锁(
sync.RWMutex
),对于读多写少的场景可以提高性能。还可以考虑使用 sync.Map
等线程安全的数据结构,减少锁的粒度。
- 自适应协程数量:根据 CPU 核心数、系统负载等动态调整工作协程的数量,提高系统资源利用率。