欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

超轻量级golang的Goroutine池

程序员文章站 2022-05-20 20:25:48
...

本文是阅读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
			}
		}
	}()
}

好了,一个协程池的最主要内容就讲完了,其他的我就不讲了

相关标签: goalng 架构