目录
  • 1. 为什么需要协程池
  • 2. 使用协程池的优点
  • 3. 设计思路
  • 4. 实现一个简单的协程池
    • 4.1 Task 任务对象
    • 4.2 Pool协程池
    • 4.3 Main函数

1. 为什么需要协程池

使用协程池的好处是减少在创建和销毁协程上所花的时间以及资源的开销,解决资源不足的问题。如果不使用协程池,有可能造成系统创建大量同类协程池而导致消耗完内存或者内存泄漏的问题。

2. 使用协程池的优点

  • 不用手动频繁的创建协程了
  • 方便统一管理,只用管理池子就行了
  • 提高响应速度,一有任务如果有刚执行完的协程就能马上去执行新任务

3. 设计思路

Task 任务对象->EntryChannel->JobsChannel <-Pool(worker)

Golang协程池的实现与应用

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
}
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。