构建的协程池实现两个目标:
1、限制协程池里开启的协程数量
2、当任务数大于协程数时,一个协程可以同时处理多个任务
3、监控是哪个协程ID处理了具体的任务
Go
package main
import (
"fmt"
"runtime"
"strconv"
"strings"
"sync"
"github.com/panjf2000/ants/v2"
)
var goRoutineID []int64 = make([]int64, 20)
func printHelloWorld(i interface{}) {
fmt.Println("hello,world:", i)
//@todo 记录当前的协程ID
gid := getGID()
goRoutineID = append(goRoutineID, gid)
}
/*
*
获取协程ID
*
*/
func getGID() int64 {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
// fmt.Printf("%s", string(b))
goidStr := strings.TrimPrefix(string(b), "goroutine ")
goidStr = goidStr[:strings.Index(goidStr, " ")]
gid, err := strconv.ParseInt(goidStr, 10, 64)
if err != nil {
return -1
}
return gid
}
func main() {
//关闭默认池
defer ants.Release()
//@定义任务总数,一个协程可以处理多个任务
runTimes := 9
var wg sync.WaitGroup
//@定义协程池容量:100
//@定义任务函数:printHelloWorld
//@协程执行完成:wg.Done:让计数器减1操作
p, _ := ants.NewPoolWithFunc(100, func(i interface{}) {
printHelloWorld(i)
wg.Done()
})
//@关闭协程池,释放工作队列
defer p.Release()
//@定义任务函数的传参,通过结构体的方式传参
callParams := struct {
name string
age int
}{
name: "zhangsan",
age: 44,
}
//@todo 提交任务
//Invoke参数将参数传递给任务函数
//wg.Add:计数器+1
for i := 0; i < runTimes; i++ {
wg.Add(1)
_ = p.Invoke(callParams)
}
//@todo 阻塞等待所有的计数器清零
wg.Wait()
//p.Running 获取当前协程池执行工作的协程数量,注意这个不等于协程池配置的数量,比如当runTimes小于协程池配置的数量时,这时候只需要开runTimes个协程就够了,所以这里的值是runTimes
fmt.Printf("running goroutines: %d\n", p.Running())
//用map去重获取我们实际使用了哪些协程ID
goRoutineBool := make(map[int64]bool, 500)
for _, v := range goRoutineID {
goRoutineBool[v] = true
}
fmt.Println("实际开启的协程ID:", goRoutineBool)
}
官方参考资料:
https://github.com/panjf2000/ants
https://pkg.go.dev/github.com/panjf2000/ants/v2@v2.9.0#section-readme