Go实现协程池

154 阅读1分钟
package main

import (
   "fmt"
   "runtime"
   "time"
)

// Task 定义一个任务类型
type Task struct {
   f func() error // 一个Task里面应该有一个具体的业务,业务名称就叫f
}

// NewTask 创建一个Task任务
func NewTask(task func() error) *Task {
   t := Task{
      f: task,
   }

   return &t
}

// Execute Task也需要一个执行任务的方法
func (t *Task) Execute() {
   t.f()
}

// --------------------------------------------以上有关Task任务的执行方法-------------------------------------------//

// Pool 定义一个协程池的类型
type Pool struct {
   // 对外的Task入口
   EntryChannel chan *Task

   // 内部的Task队列
   JobsChannel chan *Task

   // 协程池中限定的worker数量
   workerNum int
}

// NewPool 创建Pool的函数
func NewPool() *Pool {
   numCpu := runtime.NumCPU()
   // 创建一个Pool
   p := &Pool{
      EntryChannel: make(chan *Task),
      JobsChannel:  make(chan *Task),
      workerNum:    numCpu,
   }

   return p
}

// 协程池创建一个worker,并让这个worker去工作
func (p *Pool) worker(workerID int) {
   for task := range p.JobsChannel {
      // task就是当前worker从jobs channel中拿到的任务
      fmt.Printf("worker ID[%d] exectuing  ", workerID)
      task.Execute()
      fmt.Printf("worker ID[%d] exec end\n", workerID)
   }
}

// 协程池启动的方法
func (p *Pool) run() {
   // 1.根据workNum创建worker去工作
   for i := 0; i < p.workerNum; i++ {
      // 每个worker都应该是个goroutine
      go p.worker(i)
   }
   // 2.jobs channel从entry channel中取任务,将取到的任务发送给jobs channel

   for task := range p.EntryChannel {
      // 一旦有task读到
      p.JobsChannel <- task
   }
}

func main()  {
   // 1.创建一些任务
   t := NewTask(func() error {
      fmt.Printf("%v", time.Now())
      return nil
   })

   p := NewPool(4)

   go func() {
      for {
         p.EntryChannel <- t
         time.Sleep(time.Millisecond)
      }
   }()

   // 启动pool
   p.run()
}