素手烹茶|Ants - 高性能低损耗的 Goroutine 池( 二 )

< runTimes; i++ {wg.Add(1)_ = ants.Submit(syncCalculateSum) } wg.Wait() fmt.Printf("running goroutines: %d\n", ants.Running()) fmt.Printf("finish all tasks.\n")}在这个例子中 , 定义了一个简单的任务函数 demoFunc , 短暂休眠后打印 Hello World 。 在 main 函数中 , 使用了 sync.WaitGroup 来进行并发控制 , 把 demoFunc 包裹成为一个并发任务函数 syncCalculateSum 。 我们要把这个任务执行 1000 次 , 就可以通过循环 , 进行 1000 次的 ants.Submit 调用 , 把所有任务都提交到工作池执行 。 提交完成后 , 等待任务完成 。 程序在完成了 1000 次的 Hello World 打印后 , 最终完成了任务执行 。
除了使用默认的工作池外 , 我们还可以自己实例化一个工作池 , 并提供容量和任务函数 , 使用 NewPoolWithFunc 简单完成 goroutine 池的创建:
package mainimport ( "fmt" "sync" "sync/atomic" "time" "github.com/panjf2000/ants/v2")var sum int32func myFunc(i interface{}) { n := i.(int32) atomic.AddInt32( i < runTimes; i++ {wg.Add(1)_ = p.Invoke(int32(i)) } wg.Wait() fmt.Printf("running goroutines: %d\n", p.Running()) fmt.Printf("finish all tasks, result is %d\n", sum)}【素手烹茶|Ants - 高性能低损耗的 Goroutine 池】可以看到 , 使用 ants.NewPoolWithFunc , 创建了一个自定义容量和任务的函数工作池 , 任务函数可以提供一个 interface{} 参数 , 方便传递数据 。 然后 , 通过函数工作池的 Invoke 接口 , 完成任务参数的传递和任务的提交 。 在这个例子中 , 实现了从 0 到 1000 的并发求和 , 最终打印出计算结果 。
此外 , 我们还可以使用最基础的方法 NewPool 来进行 ants.Pool 结构的实例化:
p, _ := ants.NewPool(10000)NewPool 的函数签名如下:
func NewPool(size int, options ...Option) (*Pool, error)其接收一个容量参数 , 以及其他配置参数 , 返回指向 Pool 类型实例的指针和错误 。 我们可以使用 options 参数进行更为细化的配置 , 配置参数包括:

  • ExpiryDuration:清理 goroutine 的时间间隔 。 每隔一段时间 , Ants 就会对池中未被使用的 goroutine 进行清理 , 减少内存占用;
  • PreAlloc:是否在初始化工作池时预分配内存 。 对于一个超大容量 , 且任务耗时长的工作池来说 , 预分配内存可以大幅降低 goroutine 池中的内存重新分配损耗;
  • MaxBlockingTasks:阻塞任务的最大数 , 0代表无限制;
  • Nonblocking:工作池是否是非阻塞的 , 这决定了 Pool.Submit 接口在提交任务时是否会被阻塞;
  • PanicHandler:任务崩溃时的处理函数;
  • Logger:日志记录器
这些参数既可以在初始化的时候通过 Option 传递 , 也可以使用链式调用的方法实现配置叠加 , 利用 WithExpiryDuration、WithPreAlloc 等方法实现 。
Ants 的工作池的容量需要在初始化的时候提供 , 但它并不是一成不变的 , 可以通过 Tune 接口实现 goroutine 池容量的动态调整:
pool.Tune(1000)pool.Tune(100000)这个方法时线程安全的 , 不必担心动态调整带来的数据并发问题 。
在使用完成后 , 需要对工作池进行资源释放 , 一般通过 defer 机制调用:
pool.Release()也可以通过 Reboot 方法 , 把一个已经释放资源被销毁的池重新激活 , 投入使用:
pool.Reboot()Ants 以其高性能和低消耗著称 , 自然有测试依据 。 项目作者进行了 1000 万大规模并发任务执行的性能测试 , Ants 使用 70 万的 goroutine 就完成了全部任务 , 执行速度比原生 goroutine 提高了 100% , 且内存消耗保持在不使用 Pool 的 40% 。 此外 , 还进行了吞吐量测试 , 使用 Ants 的吞吐性能达到了原生 goroutine 的 2 到 6 倍 , 而内存消耗则达到 10 到 20 倍的降低 。 从测试结果来看 , Ants 的高性能特性名不虚传 。


推荐阅读