天天看點

超輕量級golang的Goroutine池大緻了解

本文是閱讀GoFrame内grpool包的了解

大緻了解

// 這是個Goroutine的 pool
type Pool struct {
	limit  int         //池子中最大數量
	count  *gtype.Int  // 目前運作的任務計數器,并發安全,郭大nb
	list   *glist.List //異步工作的隊列
	closed *gtype.Bool // 是否關閉的狀态
}

           

兩種工作方式,一種是鍊式操作,另一種非鍊式操作,這裡隻講鍊式操作

第一步初始化一個池子,可以設定池子的容量,預設不限制

//初始化并傳回池子的指針
func New(limit ...int) *Pool {
	//預設
	p := &Pool{
		limit:  -1,
		count:  gtype.NewInt(),
		list:   glist.New(true),
		closed: gtype.NewBool(),
	}
	//有傳入池子容量,指派
	if len(limit) > 0 && limit[0] > 0 {
		p.limit = limit[0]
	}
	return p
}

           

添加任務到池中

//簡單粗暴,直接傳入一個閉包方法
func (p *Pool) Add(f func()) error {
	//判斷池子是否關閉
	for p.closed.Val() {
		return errors.New("pool closed")
	}
	//添加任務到隊列中
	p.list.PushFront(f)
	// 判斷是否需要開啟新的Goroutine
	var n int
	for {
		//擷取池子運作的任務數量
		n = p.count.Val()
		//判斷目前運作的協程數量達到池子的最大容量,達到最大數量直接退出
		if p.limit != -1 && n >= p.limit {
			// No need fork new goroutine.
			return nil
		}
		//未到達,跳出循環,進行fork
		if p.count.Cas(n, n+1) {
			// Use CAS to guarantee atomicity.
			break
		}
	}
	p.fork()
	return nil
}
           

fork

//開啟一個協程,完成任務的協程會被go自動回收
func (p *Pool) fork() {
	go func() {
		//退出前減少運作協程池子容量
		defer p.count.Add(-1)

		var job interface{}
		//僞死循環,當清空隊列中的所有任務後會退出循環以及協程
		for !p.closed.Val() {
			//抛出隊列中的随機一項任務,并執行,如果抛出為空,退出目前循環,以及協程
			if job = p.list.PopBack(); job != nil {
				job.(func())()
			} else {
				return
			}
		}
	}()
}
           

好了,一個協程池的最主要内容就講完了,其他的我就不講了

繼續閱讀