• golang线程池ants-四种使用方法


    目录

    1、ants介绍

    2、使用方式汇总

    3、各种使用方式详解

    3.1 默认池

    3.2 普通模式

    3.3 带参函数

    3.4 多池多协程

    4、总结


    1、ants介绍

          众所周知,goroutine相比于线程来说,更加轻量、资源占用更少、无线程上下文切换等优势,但是也不能无节制的创建使用,如果系统中开启的goroutine过多而没有及时回收,也会造成系统内存资源耗尽。

          ants是一款高性能的协程管理池,实现了协程的创建、缓存、复用、刷新、停止等功能,同时允许开发者设置线程池中worker的数量、线程池本身的个数以及workder中的任务,从而实现更加高效的运行效果。

    github:GitHub - panjf2000/ants: 🐜🐜🐜 ants is a high-performance and low-cost goroutine pool in Go./ ants 是一个高性能且低损耗的 goroutine 池。

    2、使用方式汇总

    ants的使用有四种方式,分别如下:

    这四种使用方式,前两种最常用,基本能满足日常系统的开发需要,第四种默认池,简单的场景也可以用,但不推荐,多池的情况还没想到特别合适的应用场景。

    3、各种使用方式详解

    3.1 默认池

    ants在启动时,会默认初始化一个协程池,这部分代码位于ants.go文件中:

    1. var (
    2. // ErrLackPoolFunc will be returned when invokers don't provide function for pool.
    3. ErrLackPoolFunc = errors.New("must provide function for pool")
    4. // ErrInvalidPoolExpiry will be returned when setting a negative number as the periodic duration to purge goroutines.
    5. ErrInvalidPoolExpiry = errors.New("invalid expiry for pool")
    6. // ErrPoolClosed will be returned when submitting task to a closed pool.
    7. ErrPoolClosed = errors.New("this pool has been closed")
    8. // ErrPoolOverload will be returned when the pool is full and no workers available.
    9. ErrPoolOverload = errors.New("too many goroutines blocked on submit or Nonblocking is set")
    10. // ErrInvalidPreAllocSize will be returned when trying to set up a negative capacity under PreAlloc mode.
    11. ErrInvalidPreAllocSize = errors.New("can not set up a negative capacity under PreAlloc mode")
    12. // ErrTimeout will be returned after the operations timed out.
    13. ErrTimeout = errors.New("operation timed out")
    14. // ErrInvalidPoolIndex will be returned when trying to retrieve a pool with an invalid index.
    15. ErrInvalidPoolIndex = errors.New("invalid pool index")
    16. // ErrInvalidLoadBalancingStrategy will be returned when trying to create a MultiPool with an invalid load-balancing strategy.
    17. ErrInvalidLoadBalancingStrategy = errors.New("invalid load-balancing strategy")
    18. // workerChanCap determines whether the channel of a worker should be a buffered channel
    19. // to get the best performance. Inspired by fasthttp at
    20. // https://github.com/valyala/fasthttp/blob/master/workerpool.go#L139
    21. workerChanCap = func() int {
    22. // Use blocking channel if GOMAXPROCS=1.
    23. // This switches context from sender to receiver immediately,
    24. // which results in higher performance (under go1.5 at least).
    25. if runtime.GOMAXPROCS(0) == 1 {
    26. return 0
    27. }
    28. // Use non-blocking workerChan if GOMAXPROCS>1,
    29. // since otherwise the sender might be dragged down if the receiver is CPU-bound.
    30. return 1
    31. }()
    32. // log.Lmsgprefix is not available in go1.13, just make an identical value for it.
    33. logLmsgprefix = 64
    34. defaultLogger = Logger(log.New(os.Stderr, "[ants]: ", log.LstdFlags|logLmsgprefix|log.Lmicroseconds))
    35. // Init an instance pool when importing ants.
    36. defaultAntsPool, _ = NewPool(DefaultAntsPoolSize)
    37. )

    使用起来就比较简单了,直接往池子里提交任务即可。

    1. package main
    2. import (
    3. "fmt"
    4. "sync"
    5. "time"
    6. "github.com/panjf2000/ants/v2"
    7. )
    8. func add(d int) {
    9. sum := 0
    10. for i := 0; i < d; i++ {
    11. sum += i
    12. }
    13. }
    14. func main() {
    15. var wg sync.WaitGroup
    16. now := time.Now()
    17. for i := 0; i < 5; i++ {
    18. wg.Add(1)
    19. ants.Submit(func() {
    20. add(10000000000)
    21. wg.Done()
    22. })
    23. }
    24. wg.Wait()
    25. fmt.Println(time.Since(now))
    26. now = time.Now()
    27. for i := 0; i < 5; i++ {
    28. add(10000000000)
    29. }
    30. fmt.Println(time.Since(now))
    31. }

    运行结果:

    3.2 普通模式

    普通模式和使用默认池非常类似,但是需要自己创建一个线程池:

    p, _ := ants.NewPool(5)

    函数参数为协程池协程个数,测试代码如下:

    1. package main
    2. import (
    3. "fmt"
    4. "sync"
    5. "time"
    6. "github.com/panjf2000/ants/v2"
    7. )
    8. func add(d int) {
    9. sum := 0
    10. for i := 0; i < d; i++ {
    11. sum += i
    12. }
    13. }
    14. func main() {
    15. var wg sync.WaitGroup
    16. now := time.Now()
    17. p, _ := ants.NewPool(5)
    18. for i := 0; i < 5; i++ {
    19. wg.Add(1)
    20. p.Submit(func() {
    21. add(10000000000)
    22. wg.Done()
    23. })
    24. }
    25. wg.Wait()
    26. fmt.Println("协程池运行:", time.Since(now))
    27. now = time.Now()
    28. for i := 0; i < 5; i++ {
    29. add(10000000000)
    30. }
    31. fmt.Println("循环运行:", time.Since(now))
    32. }

    3.3 带参函数

    带参函数,重点是往worker中传递函数执行的参数,每个workder中都是同一个执行函数。

    1. package main
    2. import (
    3. "fmt"
    4. "sync"
    5. "time"
    6. "github.com/panjf2000/ants/v2"
    7. )
    8. func add(d int) {
    9. sum := 0
    10. for i := 0; i < d; i++ {
    11. sum += i
    12. }
    13. fmt.Println("the sum is: ", sum)
    14. }
    15. func main() {
    16. var wg sync.WaitGroup
    17. now := time.Now()
    18. p, _ := ants.NewPoolWithFunc(5, func(i interface{}) {
    19. add(i.(int))
    20. wg.Done()
    21. })
    22. for i := 0; i < 5; i++ {
    23. wg.Add(1)
    24. p.Invoke(1000000000)
    25. }
    26. wg.Wait()
    27. fmt.Println("循环运行:", time.Since(now))
    28. }

    运行结果:

    1. liupeng@liupengdeMacBook-Pro ants_study % go run thread_default.go
    2. the sum is: 499999999500000000
    3. the sum is: 499999999500000000
    4. the sum is: 499999999500000000
    5. the sum is: 499999999500000000
    6. the sum is: 499999999500000000
    7. 循环运行: 352.447333ms

    3.4 多池多协程

    这种模式,就是声明了多个协程池,每个池子里有多个协程在跑。

    1. package main
    2. import (
    3. "fmt"
    4. "sync"
    5. "time"
    6. "github.com/panjf2000/ants/v2"
    7. )
    8. func add(d int) {
    9. sum := 0
    10. for i := 0; i < d; i++ {
    11. sum += i
    12. }
    13. fmt.Println("the sum is: ", sum)
    14. }
    15. func main() {
    16. var wg sync.WaitGroup
    17. runTimes := 20
    18. now := time.Now()
    19. mpf, _ := ants.NewMultiPoolWithFunc(10, runTimes/10, func(i interface{}) {
    20. add(i.(int))
    21. wg.Done()
    22. }, ants.LeastTasks)
    23. for i := 0; i < runTimes; i++ {
    24. wg.Add(1)
    25. mpf.Invoke(1000000000)
    26. }
    27. wg.Wait()
    28. fmt.Println("循环运行:", time.Since(now))
    29. }

    运行记录:

    4、总结

         以上就是ants协程池所有的使用方式,3.2、3.3章节介绍的两种方式比较常用,也是推荐的使用方式,使用协程池,可以有效的控制系统硬件资源的使用,防止机器被打满,对于高并发服务非常推荐使用。

          后面会学习一下ants的源码,并整理成文档发出来,欢迎围观。

  • 相关阅读:
    【合集】Spring Cloud 组件——架构进化史话 & Nacos,OpenFeign,Ribbon,Sentinel,Gateway . . .
    《python程序语言设计》2018版第5章第55题利用turtle黑白棋盘。可读性还是最重要的。
    Linux Shell重定向 管道命令 awk编程 sed文件操作高阶函数
    awk入门教程
    pip出现的问题
    ES6——知识点记录
    刷题笔记25——图论课程表
    Dockerfile - USER 指令详解
    地图双屏鼠标跟随效果
    Scala配置和Spark配置以及Scala一些函数的用法(附带词频统计实例)
  • 原文地址:https://blog.csdn.net/liupenglove/article/details/139048538