GO 協程池 - Goroutine複用、限制數量

創建一個協成複用,限制協成數量的協成池

package pool

import (
	"fmt"
)

type Pool interface {
	Schedule(task func()) error
}

type pool struct {
	work chan func()
	sem  chan struct{} // 計數,限制協成數
}

func New(size int) Pool {
	return &pool{
		work: make(chan func()),
		sem:  make(chan struct{}, size),
	}
}
func (p *pool) Schedule(task func()) error {
	select {
	case p.work <- task:
	case p.sem <- struct{}{}:
		go p.worker(task)
	}
	return nil
}
func (p *pool) worker(task func()) {
	defer func() { <-p.sem }()
	for {
		task()
		task = <-p.work
	}
}

1. p.work時無緩衝,所以第一次調用Schedule時case p.work <- task: 由於沒有協成讀work,就不會寫入,就爲false,
2. p.sem因爲有緩衝區,不需要有讀協成讀就可以寫入,所以會執行case p.sem <- struct{}{},往sem寫入一個空對象,接着通過go p.workder(task)開啓一個協成處理task。
3. task處理結束後,協成不銷燬,會停在task = <-p.work等待接收p.work裏的任務
2. 第二次調用Schedule,如果第一次創建的協成等待接收新的task(task = <-p.work),就會執行case p.work <- task,往work的channel寫數據,協成就能從p.work取到(task = <-p.work)task執行,不會開啓新的協成。
3. 如果task執行時間比較久,第二次調用Schedule時,task()還未執行完,也就是還未執行到task = <-p.work,那麼case p.work <- task將無法寫入,當p.sem緩衝區沒滿(還未達到限制size)就會執行case p.sem <- struct{}{},開啓新的協成執行task.
4. 當p.sem緩衝區滿了,也就是說達到限制的最大數時,Schedule將會pending,直到某個協成執行到task = <-p.work接收任務
5. defer func() { <-p.sem }()是用在回收,在一些情況下,希望協成銷燬,就可以跳出for循環,sem讀出數據,也就是線程數數-1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章