超轻量级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
}
}
}()
}
好了,一个协程池的最主要内容就讲完了,其他的我就不讲了