1. 为什么需要协程池
使用协程池的好处是减少在创建和销毁协程上所花的时间以及资源的开销,解决资源不足的问题。如果不使用协程池,有可能造成系统创建大量同类协程池而导致消耗完内存或者内存泄漏的问题。
2. 使用协程池的优点
- 不用手动频繁的创建协程了
- 方便统一管理,只用管理池子就行了
- 提高响应速度,一有任务如果有刚执行完的协程就能马上去执行新任务
3. 设计思路
Task 任务对象->EntryChannel->JobsChannel <-Pool(worker)
4. 实现一个简单的协程池
4.1 Task 任务对象
type Task struct {
// Task方法 任务
method func() error
// 可以扩展
}
// NewTask 创建一个Task
func NewTask(method func() error) *Task {
return &Task{
method: method,
}
}
// Execute 任务执行
func (t *Task) Execute() {
err := t.method()
if err != nil {
panic(err)
}
}
4.2 Pool协程池
// 定义一个协程池
type Pool struct {
// 对外的Task入口
EntryChannel chan *Task
// 对内的Task队列
JobsChannel chan *Task
// 协程池的最大work数量
WorkerNum int
}
// NewPool 创建Pool的函数
func NewPool(cap int) *Pool{
return &Pool{
EntryChannel: make(chan *Task),
JobsChannel: make(chan *Task),
WorkerNum: cap,
}
}
// 协程池创建一个Worker
func (p *Pool)worker(workID int){
for task:=range p.JobsChannel{
task.Execute() //取到任务就执行
fmt.Println("worker_id 为",workID)
}
}
// 让协程池开始真正的工作
func (p *Pool)run() {
// 根据创建协程池的大小来创建协程工作
for i := 0; i < p.WorkerNum; i++ {
go p.worker(i+1)
}
// 不断遍历外部的任务然后丢入到内部的队列去运行
for task := range p.EntryChannel {
p.JobsChannel<-task
}
}
4.3 Main函数
// 主函数 测试
func main(){
// 创建一些任务
task:=NewTask(PrintTimeNow)
// 创建协程池
pool:=NewPool(4)
taskNum:=0
go func(taskNum int) {
for{
// 不断的向池子里写入任务task,任务主要是打印当前时间
pool.EntryChannel<-task
// atomic.AddInt32(&taskNum,1)
taskNum+=1
fmt.Println("当前一共执行了",taskNum,"个任务")
}
}(taskNum)
pool.run()
}
// 业务逻辑
func PrintTimeNow()( err error){
fmt.Println(time.Now())
return
}
到此这篇关于Golang协程池的实现与应用的文章就介绍到这了,更多相关Go协程池内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!