超轻量级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
			}
		}
	}()
}

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

猜你喜欢

转载自blog.csdn.net/weixin_39998006/article/details/107065292
今日推荐