grpool goroutine池协程管理

 更新时间:2022年06月08日 10:38:39   作者:​ 王中阳Go   ​  
这篇文章主要介绍了grpool goroutine池协程管理,goroutine协程非常轻量级,这也是为什么go支持高并发,但是goroutine频繁创建销毁对GC的压力比较大,文章围绕主题展开详细的内容介绍,需要的小伙伴可以参考一下

前言

goroutine协程非常轻量级,这也是为什么go支持高并发,但是goroutine频繁创建销毁对GC的压力比较大。

grpool的作用就是复用goroutine,减少频繁创建销毁的性能消耗。

名词概念

Pool: goroutine池,用于管理若干可复用的goroutine协程资源

Worker: 池对象中参与任务执行的goroutine,一个worker可以执行若干个job,直到队列中再无等待的job

Job:添加到池对象的任务队列中等待执行的任务,是一个func()方法,一个job同时只能被一个worker获取并执行。

使用示例

使用默认的协程池,限制100个协程执行1000个任务

pool.Size() 获得当前工作的协程数量

pool.Jobs() 获得当前池中待处理的任务数量

package main
import (
   "fmt"
   "github.com/gogf/gf/os/grpool"
   "github.com/gogf/gf/os/gtimer"
   "sync"
   "time"
)
func main() {
   pool := grpool.New(100)
   //添加1千个任务
   for i := 0; i < 1000; i++ {
      _ = pool.Add(job)
   }
   fmt.Println("worker:", pool.Size()) //当前工作的协程数量
   fmt.Println("jobs:", pool.Jobs())   //当前池中待处理的任务数量

   gtimer.SetInterval(time.Second, func() {
      fmt.Println("worker:", pool.Size()) //当前工作的协程数
      fmt.Println("jobs:", pool.Jobs())   //当前池中待处理的任务数
   })
   //阻止进程结束
   select {}
}
//任务方法
func job() {
   time.Sleep(time.Second)
}

打印结果:

是不是灰常简单~

踩坑之旅

一个简单的场景,请使用协程打印0~9。

常犯的错误

大家看下面的代码有没有问题,请预测一下打印结果。

wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
   wg.Add(1)
   go func() {
      fmt.Println(i)
      wg.Done()
   }()
}
wg.Wait()

不用着急看答案

猜一下打印结果是什么

打印结果:

分析原因

对于异步线程/协程来讲,函数进行异步执行注册时,该函数并未真正开始执行(注册时只在goroutine的栈中保存了变量i的内存地址),而一旦开始执行时函数才会去读取变量i的值,而这个时候变量i的值已经自增到了9

正确写法:

wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
   wg.Add(1)
   go func(v int) {
      fmt.Println(v)
      wg.Done()
   }(i)
}
wg.Wait()

打印结果:

使用grpool

使用grpool和使用go一样,都需要把当前变量i的值赋值给一个不会改变的临时变量,在函数中使用该临时变量而不是直接使用变量i

错误代码

wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
   wg.Add(1)
   _ = grpool.Add(func() {
      fmt.Println(i) //打印结果都是9
      wg.Done()
   })
}
wg.Wait()

打印结果:

正确代码

wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
   wg.Add(1)
   v := i //grpoll.add() 的参数只能是不带参数的匿名函数 因此只能以设置临时变量的方式赋值
   _ = grpool.Add(func() {
      fmt.Println(v)
      wg.Done()
   })
}
wg.Wait()

打印结果:

总结

通过这篇文章我们了解到:grpool的作用就是复用goroutine,减少频繁创建销毁的性能消耗。也了解到使用协程容易犯的错误,以及用临时变量的方式来解决问题。

说句题外话:grpool的基础概念:Pool、Worke、Job 和我之前设计的派单系统简直一模一样。

到此这篇关于grpool goroutine池协程管理的文章就介绍到这了,更多相关grpool goroutine池 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang中sync.Map并发创建、读取问题实战记录

    golang中sync.Map并发创建、读取问题实战记录

    这篇文章主要给大家介绍了关于golang中sync.Map并发创建、读取问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • Go的os/exec执行超时导致程序死机的解决方案

    Go的os/exec执行超时导致程序死机的解决方案

    这篇文章主要介绍了Go的os/exec执行超时导致程序死机的几种解决方案,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-04-04
  • Go标准库之Requests的介绍与基本使用

    Go标准库之Requests的介绍与基本使用

    Python中的Requests库非常强大,所以Go开发者模仿Python的Requests库,由此诞生了Grequests库,本文主要介绍了Requests的基本使用,有需要的可以参考下
    2024-04-04
  • Go 语言中的 http.FileSystem详细解析

    Go 语言中的 http.FileSystem详细解析

    在本文中,我们深入探讨了 Go 语言中的 http.FileSystem 接口,并介绍了它的基本原理、使用方法以及实际应用场景,感兴趣的朋友跟随小编一起看看吧
    2024-03-03
  • Go语言函数学习教程

    Go语言函数学习教程

    这篇文章主要介绍了Go语言函数基本用法,结合实例形式分析了Go语言函数的格式、定义、使用方法与相关注意事项,需要的朋友可以参考下
    2016-07-07
  • golang进行简单权限认证的实现

    golang进行简单权限认证的实现

    本文主要介绍了golang简单权限认证的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Go疑难杂症讲解之为什么nil不等于nil

    Go疑难杂症讲解之为什么nil不等于nil

    在日常开发中,可能一不小心就会掉进 Go 语言的某些陷阱里,而本文要介绍的 nil ≠ nil 问题,感兴趣的小伙伴可以跟随小编一起了解一下
    2022-10-10
  • 用gomock进行mock测试的方法示例

    用gomock进行mock测试的方法示例

    go-mock是专门为go语言开发的mock库,该库使用方式简单,支持自动生成代码,这篇文章主要介绍了用gomock进行mock测试的方法示例,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • golang中获取变量类型的方法总结

    golang中获取变量类型的方法总结

    golang中是没有提供内置函数来获取变量的类型的,但是通过一定的方式也可以获取,下面主要给大家介绍了几个golang获取变量类型的几种方式,需要的朋友可以参考下
    2025-03-03
  • go doudou开发gRPC服务快速上手实现详解

    go doudou开发gRPC服务快速上手实现详解

    这篇文章主要为大家介绍了go doudou开发gRPC服务快速上手实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12

最新评论