golang协程池(goroutine池)ants库实践

 golang中goroutine由运行时管理,使用go关键字就可以方便快捷的创建一个goroutine,受限于服务器硬件内存大小,如果不对goroutine数量进行限制,会出现Out of Memory错误。但是goroutine泄漏引发的血案,想必各位gopher都经历过,通过协程池限制goroutine数一个有效避免泄漏的手段,但是自己手动实现一个协程池,总是会兼顾不到各种场景,比如释放,处理panic,动态扩容等。那么ants是公认的优秀实现协程池。

ants简介
   ants是一个高性能的 goroutine 池,实现了对大规模 goroutine 的调度管理、goroutine 复用,允许使用者在开发并发程序的时候限制 goroutine 数量,复用资源,达到更高效执行任务的效果

功能
自动调度海量的 goroutines,复用 goroutines
定期清理过期的 goroutines,进一步节省资源
提供了大量有用的接口:任务提交、获取运行中的 goroutine 数量、动态调整 Pool 大小、释放 Pool、重启 Pool
优雅处理 panic,防止程序崩溃
资源复用,极大节省内存使用量;在大规模批量并发任务场景下比原生 goroutine 并发具有更高的性能
非阻塞机制

Go 语言最大的特色之一,就是其从语言的层面支持并发。Go 语言使用了其特有的 goroutine 作为最基本的并发执行单元,以协程的方式,实现了更加轻量和高效的并发执行。然而,goroutine 缺乏一个高级的管理机制,原生情况下使用,要实现动态调整数量、内存资源复用、错误处理等,往往需要编写比较多的底层代码逻辑。Ants,这个 goroutine 池实现,提供了对于大规模 goroutine 的管理功能,相比原生实现,资源使用率和执行性能都有了很大的提升。

ants pool

简介

Ants,是 panjf2000 在 Github 上开源的高性能 goroutine 池,项目位于 ,目前版本为 v2.4.0。Ants 实现了对于大规模 goroutine 的调度管理和复用,允许使用者在开发 Golang 并发程序时限制 goroutine 数量,复用资源,达到更高效执行任务的效果。Ants 提供了大量有用的接口,包括:任务提交、获取运行中的 goroutine 数量、动态调整池带下、释放和重启池等。Ants 通过优秀的资源复用策略,极大地节省内存使用量,在大规模批量并发任务场景下,比原生的 goroutine 实现的并发具有更高的性能。

Github项目

安装

Ants 使用 Go 语言开发,需要 Go 1.8.x 以上。Ants 目前同时维护 v1 和 v2 版本,安装 v1 版本:

 go get -u github.com/panjf2000/ants  

v2 版本需要使用 go module 支持,开启 GO111MODULE=on:

 go get -u github.com/panjf2000/ants/v2  

godoc文档

示例

Ants 对于任务的执行原理比较直观,通过一个工作池的形式维护 goroutine 集合。当向工作池提交任务时,从池中取出 worker 来执行。如果已经存在可用的 goroutine 了,那么直接开始执行,如果没有,则需要判断是否已经达到容量上限。如果还没有超过,那就意味着可用的 worker 比容量更少,此时启动新的 worker 来执行。而如果容量已经用完,就依据是否为阻塞模式,来马上返回,或是阻塞等待。

ants工作池等待

当任务执行完毕,对应的 worker 就会得到释放,重新回到池中,等待下一个任务的调度,实现 goroutine 的复用。

ants复用

完整的工作池 worker 调度的逻辑和流程如下:

ants任务执行流程

Ants 支持不同的使用方式,可以直接使用 Submit 接口,使用默认配置的工作池完成任务执行。Submit 函数的定义如下:

 func Submit(task func()) error  

通过提供一个函数类型的任务参数,来把任务提交到工作池执行。我们来看一个简单的使用例子:

 package mainimport ("fmt""sync""time""github.com/panjf2000/ants/v2"
)func demoFunc() {time.Sleep(10 * time.Millisecond)fmt.Println("Hello World!")
}func main() {defer ants.Release()runTimes := 1000var wg sync.WaitGroupsyncCalculateSum := func() {demoFunc()wg.Done()}for i := 0; i < 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(∑, n)fmt.Printf("run with %d\n", n)
}func main() {runTimes := 1000// 创建一个容量为10的goroutine池p, _ := ants.NewPoolWithFunc(10, func(i interface{}) {myFunc(i)wg.Done()})defer p.Release()for i := 0; 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.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 的高性能特性名不虚传。

性能测试

总结

Ants 作为一个高性能 goroutine 池,提供了比原生 goroutine 实现更为高级的调度管理和复用机制,抽象层次更高,且充分利用池化策略,使用尽可能少的 goroutine 数量和内存占用,以更快的速度完成并发任务的执行,在大规模和高吞吐场景下,具备很强的性能优势。Ants 项目代码整洁,注释详尽,文档丰富,对于 goroutine 并发模型有较深的理解,对相关领域感兴趣的开发者可以进行参考学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/84078.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

易服客工作室:初学者的终极WordPress SEO教程(入门指导)

改善WordPress SEO对于获得更多网站流量至关重要。可悲的是&#xff0c;大多数WordPress SEO指南对于新用户来说太技术性了。 如果您认真考虑增加网站流量&#xff0c;则需要注意WordPress SEO最佳做法。 在本WordPress SEO教程中&#xff0c;我们将分享WordPress SEO的主要技…

创建Springboot+vue3项目

项目概述创建springboot项目加入mybatis-plus支持1.加入依赖代码2.创建数据库实例3.yml文件的配置4.编写测试代码5.测试结果 创建vue项目报错错误一错误二错误三 项目概述 后端&#xff1a;Springboot、mybatis-plus、java 前端&#xff1a;nodejs、vue脚手架、element-ui 数据…

【Spring Boot 源码学习】自动装配流程源码解析(上)

自动装配流程源码解析&#xff08;上&#xff09; 引言往期内容主要内容1. 自动配置开关2. 加载自动配置组件3. 自动配置组件去重 总结 引言 上篇博文&#xff0c;笔者带大家从整体上了解了AutoConfigurationImportSelector 自动装配逻辑的核心功能及流程&#xff0c;由于篇幅…

HCIP-linux和kvm(ks配置文件自动化安装及console连虚拟机有问题)

1、linux linux安装教程参考&#xff0c;https://blog.51cto.com/cloudcs/5245337 yum源配置 本地yum源配置&#xff1a; 8版本配置&#xff1a;将光盘iso挂载到某个目录&#xff0c;/dev/cdrom是/dev/sr0软链接&#xff0c;# mount /dev/cdrom /mnt&#xff0c;# ls /mnt Ap…

C#导入数据使用Task异步处理耗时任务

C#多线程中&#xff0c;我们可以使用async和await来异步处理耗时任务。 现在我们打开一个Excel表格&#xff0c;将Excel表格的每一行数据进行处理&#xff0c;并存储到数据库中 新建Windows应用程序DataImportDemo&#xff0c;.net framework 4.6.1 将默认的Form1重命名为Fo…

数组slice、splice字符串substr、split

一、定义 这篇文章主要对数组操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;slice、splice。对字符串操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;substr、split (一)、数组 slice:可以操作的数据类型有&#xff1a;数组字符串 splice:数组 操作数组…

小程序wx:else提示 Bad attr `wx

问题&#xff1a;以下wx:for里的wx:if &#xff0c; wx:else 会报这个错&#xff1a;Bad attr wx <scroll-view class"scroll1" scroll-x enable-flex"true"><view wx:if"{{playlist.length>0}}" class"item" wx:for"…

SonarQube安装与Java、PHP代码质量分析扫描

文章目录 1、下载安装1.1、SonarQube下载1.2、SonarQube安装1.3、SonarQube中文汉化1.4、SonarScanner扫描器 2、扫描项目2.1、java代码扫描2.2、php代码扫描 1、下载安装 SonarQube负责存储代码数据、收集数据、分析代码和生成报告等。 1.1、SonarQube下载 下载地址&#x…

MPP架构和Hadoop架构的区别

1. 架构的介绍 mpp架构是将许多数据库通过网络连接起来&#xff0c;相当于将一个个垂直系统横向连接&#xff0c;形成一个统一对外的服务的分布式数据库系统。每个节点由一个单机数据库系统独立管理和操作该物理机上的的所有资源&#xff08;CPU&#xff0c;内存等&#xff09…

【QT】 QT开发PDF阅读器

很高兴在雪易的CSDN遇见你 &#xff0c;给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享QT开发PDF阅读器技术&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xff0c;一起进步&#xff01; 你的点…

使用chatGPT-4 畅聊量子物理学

与chatGPT深入研究起源、基本概念&#xff0c;以及海森堡、德布罗意、薛定谔、玻尔、爱因斯坦和狄拉克如何得出他们的想法和方程。 1965 年&#xff0c;费曼&#xff08;左&#xff09;与朱利安施温格&#xff08;未显示&#xff09;和朝永信一郎&#xff08;右&#xff09;分享…

数据分析-python学习 (1)numpy相关

内容为&#xff1a;https://juejin.cn/book/7240731597035864121的学习笔记 导包 import numpy as np numpy数组创建 创建全0数组&#xff0c;正态分布、随机数组等就不说了&#xff0c;提供了相应的方法通过已有数据创建有两种 arr1np.array([1,2,3,4,5]) 或者datanp.loadt…

当我准备出门时,发现了......我可以用Python实现12306自动买票

前言 不知道大家有没有之前碰到这样的情况&#xff0c;打算去某一个地方当你规划好了时间准备去买票的时候&#xff0c;你想要的那一列往往没有你想要的票了&#xff0c;尤其是国庆七天假和春节半月假&#xff0c;有时候甚至买不到规定计划时间内的票&#xff0c;真的是太烦躁…

列队 Queue 接口概述

在Java中&#xff0c;Queue&#xff08;队列&#xff09;是一种基本的数据结构&#xff0c;用于按照先进先出&#xff08;FIFO&#xff09;的顺序存储元素。Java提供了多种实现Queue接口的类&#xff0c;以下是几种常见的实现方式&#xff1a; LinkedList&#xff1a;LinkedLis…

RISC-V公测平台发布 · 使用YCSB测试SG2042上的MySQL性能

实验介绍&#xff1a; YCSB&#xff08;全称为Yahoo! Cloud Serving Benchmark&#xff09;&#xff0c;该性能测试工具由Java语言编写&#xff08;在之前的MC文章中也提到过这个&#xff0c;如果没看过的读者可以去看看之前MC那一期&#xff09;&#xff0c;主要用于云端或者…

【位操作符的几种题型】

位操作符的几种题型 目录 题型一&#xff1a;寻找“单身狗”。 题型二&#xff1a;计算一个数在二进制中1的个数 题型三&#xff1a;不允许创建临时变量&#xff0c;交换两个整数的内容 题型一&#xff1a;寻找“单身狗”。 1.1题目解析 在一个整型数组中&#xff0c;只有…

SUB-1G SOC芯片DP4306F 32 位 ARM Cortex-M0+内核替代CMT2380F32

DP4306F是一款高性能低功耗的单片集成收发机&#xff0c;集成MO核MCU&#xff0c;工作频率可覆盖200MHiz^ 1000MHz。 支持230/408/433/470/868/915频段。该芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK解调器等功能模块。通过SPI接口可以对输出功率、频道选…

element-plus的日期选择器限定选择范围

目录 前言一、最近30天总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; element-plus的日期选择器限定选择范围&#xff0c;由于数据的获取范围限定&#xff0c;需要前端处理一下日期的选择范围 提示&#xff1a;以下是本篇文章正文内容&#xff0c…

软考高级之系统架构师之数据通信与计算机网络

概念 OSPF 在划分区域之后&#xff0c;OSPF网络中的非主干区域中的路由器对于到外部网络的路由&#xff0c;一定要通过ABR(区域边界路由器)来转发&#xff0c;既然如此&#xff0c;对于区域内的路由器来说&#xff0c;就没有必要知道通往外部网络的详细路由&#xff0c;只要由…

【计算机网络】概述及数据链路层

每一层只依赖于下一层所提供的服务&#xff0c;使得各层之间相互独立、灵活性好&#xff0c;已于实现和维护&#xff0c;并能促进标准化工作。 应用层&#xff1a;通过应用进程间的交互完成特定的网络应用&#xff0c;HTTP、FTP、DNS&#xff0c;应用层交互的数据单元被称为报…