
























ants 是 Go 语言中一个非常流行的高性能 Goroutine(协程)池库。它的核心作用是管理和复用 Goroutine,避免在高并发场景下因无限制地创建和销毁协程而导致系统资源耗尽、内存飙升或 GC(垃圾回收)压力过大。
以下是关于 ants 库的详细介绍与使用指南:
首先,通过以下命令安装 ants:
go get -u github.com/panjf2000/ants/v2
ants 提供了两种主要的使用模式:普通协程池 和 带函数的协程池。
NewPool)适用于提交任意无参数的函数作为任务。通常需要结合 sync.WaitGroup 来同步等待所有任务完成。
package main
import (
"fmt"
"sync"
"time"
"github.com/panjf2000/ants/v2"
)
func main() {
var wg sync.WaitGroup
// 创建一个容量为 10 的协程池
pool, _ := ants.NewPool(10)
defer pool.Release() // 确保程序结束时释放池资源
for i := 0; i < 20; i++ {
wg.Add(1)
// 注意闭包传参问题,将 i 赋值给局部变量
idx := i
pool.Submit(func() {
defer wg.Done()
fmt.Printf("Task %d is running\n", idx)
time.Sleep(time.Second) // 模拟耗时操作
})
}
wg.Wait()
fmt.Println("All tasks finished")
}
NewPoolWithFunc)适用于需要向任务传递参数的场景。通过预定义一个处理函数,提交任务时直接传入参数即可,无需频繁创建闭包,性能更高。
package main
import (
"fmt"
"time"
"github.com/panjf2000/ants/v2"
)
func main() {
// 定义一个处理任务的函数
taskFunc := func(i interface{}) {
n := i.(int)
fmt.Printf("Task with param %d is running\n", n)
time.Sleep(time.Second)
}
// 创建一个带函数的协程池
pool, _ := ants.NewPoolWithFunc(10, taskFunc)
defer pool.Release()
for i := 0; i < 20; i++ {
// 使用 Invoke 提交带有参数的任务
pool.Invoke(i)
}
// 等待所有任务执行完毕
pool.Wait()
fmt.Println("All tasks finished")
}
在创建协程池时,ants 支持多种自定义配置来满足不同的业务需求:
Tune):可以在运行时动态改变协程池的大小,适应系统负载的变化。pool.Tune(20) // 将池容量调整为 20
WithPreAlloc):如果在高并发启动时希望立即拥有指定数量的工作协程,可以开启此选项,减少初期的调度延迟。pool, _ := ants.NewPool(10, ants.WithPreAlloc(true))
WithNonblocking):默认情况下,当池满时新任务会阻塞等待。开启非阻塞模式后,如果池已满,提交任务会直接返回错误 (ants.ErrPoolOverload)。pool, _ := ants.NewPool(10, ants.WithNonblocking(true))
WithPanicHandler):防止某个任务发生 panic 导致整个协程崩溃。你可以自定义捕获和处理逻辑。pool, _ := ants.NewPool(10, ants.WithPanicHandler(func(err interface{}) {
fmt.Println("Recovered from panic:", err)
}))
WithExpiryDuration):控制空闲的 worker 存活多久后被自动清理,以释放内存。ants 提供了丰富的接口来获取协程池的实时状态,方便进行监控和调试:
| 方法 | 说明 |
|---|---|
pool.Running() |
获取当前正在工作的 Goroutine 数量 |
pool.Free() |
获取当前池中空闲可用的 Goroutine 数量 |
pool.Cap() |
获取协程池的最大容量 |
pool.Wait() |
仅在使用 NewPoolWithFunc 时可用,用于阻塞等待所有任务完成 |
defer pool.Release() 来关闭协程池。一旦调用 Release(),该池将无法再接受新的任务,否则会触发 panic。Submit 提交任务时,如果是循环提交,一定要注意 Go 语言闭包的变量捕获问题(建议使用局部变量接收循环变量),否则可能导致多个任务拿到相同的参数。此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。