Go基础学习-协程池的设计思路

协程池

  • 通常会使用可以指定启动的goroutine数量–worker pool模式,控制goroutine的数量,防止goroutine泄漏和暴涨。

简易worker pool

  • 使用goroutine和channel实现一个计算int64随机数各位数和的程序。
    1. 开启一个goroutine生成int64类型的随机数,发送到jobChan
    2. 开启24个goroutine从jobChan中取出随机数计算各位数的和,将结果发送到resultChan
    3. 主goroutine从resultChan取出结果并打印到终端输出
var jobChan chan int64
var resultChan chan int64

func main() {
	jobChan = make(chan int64, 100)
	resultChan = make(chan int64, 50)
	go proInt(jobChan)
	for i := 1; i <= 24; i++ { //worker pool
		go spendInt(jobChan, resultChan)
	}
	for x := range resultChan {
		time.Sleep(time.Second)
		x = <-resultChan
		fmt.Println(x)
	}
}

//生产者 生成int64类型的随机数,发送到jobChan
func proInt(jobChan chan<- int64) {
	for {
		jobChan <- rand.Int63()
	}

}

//消费者 从jobChan中取出随机数计算各位数的和,将结果发送到resultChan
func spendInt(jobChan <-chan int64, resultChan chan<- int64) {
	for {
		job := <-jobChan
		var sum = int64(0)
		for job > 0 {
			i := job % 10
			job = job / 10
			sum += i
		}
		resultChan <- sum
	}
}

协程池的设计思路

在这里插入图片描述

//Task 定义任务对象
type Task struct {
	f func() error //任务要具体执行的业务 叫f
}

//WorkerPool 定义协程池对象
type WorkerPool struct {
	JobChannel   chan *Task
	EntryChannel chan *Task
	MaxNum       int
}

//NewTask 创建一个任务实例
func NewTask(fun func() error) (task *Task) {
	task = &Task{
		f: fun,
	}
	return
}

//Execute 执行任务实体中的方法
func (t *Task) Execute() {
	t.f() //调用任务中已经绑定的方法
}

//NewPool 创建一个协程池实例
func NewPool(maxNum int) (pool *WorkerPool) {
	pool = &WorkerPool{
		JobChannel:   make(chan *Task),
		EntryChannel: make(chan *Task),
		MaxNum:       maxNum,
	}
	return
}

//Worker 协程池创建一个worker让worker去执行任务
func (w *WorkerPool) Worker(workID int) {
	for task := range w.JobChannel { //永久的从jobchannel中拿取任务去执行
		task.Execute()
		fmt.Println("worker ID:", workID, "has execute a task")
	}
}

func (w *WorkerPool) run() {
	//1.根据maxNum来创建对应数据的worker来工作
	for i := 0; i < w.MaxNum; i++ {
		go w.Worker(i)
	}
	//2.从EntryChannel中取任务,将任务发送给jobchannel
	for tast := range w.EntryChannel {
		w.JobChannel <- tast
	}
}

//testTask 测试使用 模拟具体任务
func testTask() error {
	fmt.Println(time.Now().Second())
	return nil
}

func main() {
	//1.创建一些具体任务
	t := NewTask(testTask)
	//2.创建一个workPool实例
	p := NewPool(6)
	//3.将创建的任务流到entryChannel中
	go func() {
		for { //不断的将任务给写道接口通道中
			p.EntryChannel <- t
		}
	}()
	//4.启动pool去执行
	p.run()
}

猜你喜欢

转载自blog.csdn.net/wzb_wzt/article/details/107387120