简介
ants是广泛使用的一个开源项目,提供了丰富的协程池管理功能
demo try
package main
import (
"fmt"
"time"
"github.com/panjf2000/ants/v2"
)
func main() {
defer ants.Release()
printDemo := func() {
fmt.Println("print demo in ants")
}
for i := 0; i < 10; i++ {
ants.Submit(printDemo)
}
time.Sleep(time.Second * 5)
printArgs := func(i interface{}) {
fmt.Println("print args in ants with args:", i)
}
p, err := ants.NewPoolWithFunc(10, printArgs)
if err != nil {
fmt.Println(err)
return
}
for i := 0; i < 15; i++ {
if err = p.Invoke(i); err != nil {
fmt.Println(err)
}
}
time.Sleep(time.Second * 5)
}
一探究竟
Pool
Pool定义了协程池的接口,包含了worker的队列结构,通过Submit()提交一个函数。ants是pool的一个默认实现。
worker
worker记录着待执行的任务信息和关联的协程池信息
workerQueue
workerQueue定义了worker队列的接口,有两个默认的实现:workerStack、loopQueue,顾名思义,一个是栈结构,一个是循环数组结构。
核心逻辑
NewPool()
新增待执行任务时,通过pool的Submit方法,将任务信息记录到一个队列中的一个worker
w, err := p.retrieveWorker()
if w != nil {
w.inputFunc(task)
}
pool的retrieveWorker方法,会获取一个worker,并调用worker的run方法
// do something
w = p.workerCache.Get().(*goWorker)
w.run()
// do something
在worker的run方法中,会运行待执行的任务,然后回收worker到pool的workerCache
defer func() {
w.pool.addRunning(-1)
w.pool.workerCache.Put(w)
// ...
}
// ...
for f := range w.task {
if f == nil {
return
}
f()
if ok := w.pool.revertWorker(w); !ok {
return
}
}
NewPoolWithFunc
通过NewPoolWithFunc方法初始化协程池时,会将待执行的函数存储到pool的poolFunc方法。任务信息通过Invoke 传入参数。此时,会获取一个worker,并保存入参信息
func (p *PoolWithFunc) Invoke(args interface{}) error {
if p.IsClosed() {
return ErrPoolClosed
}
w, err := p.retrieveWorker()
if w != nil {
w.inputParam(args)
}
return err
}
类似的,w.inputParam会运行任务
// ...
defer func() {
w.pool.addRunning(-1)
w.pool.workerCache.Put(w)
if p := recover(); p != nil {
// ...
}
// ...
}()
// ...
for args := range w.args {
if args == nil {
return
}
w.pool.poolFunc(args)
if ok := w.pool.revertWorker(w); !ok {
return
}
}
// ...
相关配置
pool支持logger、panicHandler、是否阻塞、最大阻塞任务等。
扩展
此外,ants还提供了multiPool类,初始化多个协程池,可以根据预先定义的策略:轮询或者最少使用策略,从多个协程池中获取worker