golang协程池之ants

60 阅读2分钟

简介

github.com/panjf2000/a…

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)
}

一探究竟

image.png

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