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

news2024/11/23 11:39:54

 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 main

import (
	"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 := 1000
	var wg sync.WaitGroup
	syncCalculateSum := 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 main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/panjf2000/ants/v2"
)

var sum int32

func 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.coloradmin.cn/o/850796.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式任务调度平台XXL-JOB学习笔记-helloworld运行

环境&#xff1a;win10 eclipse java17 mysql8.0.17 xxl-job 2.4 源码&#xff1a;https://github.com/xuxueli/xxl-job/ 导入时按Existing Maven Projects导入&#xff0c;先导入xxl-job-admin&#xff08;管理平台&#xff09;和xxl-job-executor-sample-springboot&#x…

帆软设计器大坑:导出的模板会改变数据集的类型

今天早上在调试一个帆软决策报表&#xff08;*.frm&#xff09;中的可视化图表。无意中发现之前自己做的数据源变成了内置数据源&#xff08;ps.不会更新的静态数据&#xff09;。 查看了原来复制用的模板&#xff1a; 另存为模板&#xff08;含数据&#xff09;&#xff0c;放…

LVS-DR模式集群构建过程演示

一、工作原理 LVS的工作原理 1.当用户向负载均衡调度器&#xff08;Director Server&#xff09;发起请求&#xff0c;调度器将请求发往至内核空间 2.PREROUTING链首先会接收到用户请求&#xff0c;判断目标IP确定是本机IP&#xff0c;将数据包发往INPUT链 3.IPVS是工作在IN…

THS4301 振荡问题排查及解决过程

项目背景简介: 本项目是基于一款微弱信号处理前级模拟电路设计方案。 问题描述: 在生产标定中,发现以前的程序在小量程标定后,切换到差分和单端后,两者的直流偏置不一样,且切换到差分输入时,能发现有振荡现象(有设备单端输入也有振荡); 排查分析过程: 1)首先可以…

车云一体化系统基础理论

车云一体化系统基础理论 介绍目标正文 参考文档 介绍 最近在调研车云链路一体化的整套解决方案&#xff0c;涉及分布式消息队列&#xff08;RocketMQ&#xff09;、分布式存储&#xff08;Doris&#xff09;、离线数据处理&#xff08;Spark&#xff09;、用户行为日志分析&am…

二级python和二级c哪个简单,二级c语言和二级python

大家好&#xff0c;小编为大家解答二级c语言和二级office一起报可以吗的问题。很多人还不知道计算机二级c语言和python哪个好考&#xff0c;现在让我们一起来看看吧&#xff01; 介绍Python有很多库和使用Qt编写的接口,这自然创建c调用Python的需求。一路摸索,充满艰辛的添加头…

机器学习笔记:李宏毅ChatGPT:生成式学习的两种策略

1 策略1 “各个击破”——autoregressive model “各个击破”——一个一个生成出来 2 策略2 &#xff1a; “一次到位”——non-autoregressve model 一步到位&#xff0c;全部生成出来 2.1 non-autoregressive model 如何确定长度&#xff1f; 两种策略 策略1&#xff1a;始…

Android OkHttp源码分析--分发器

OkHttp是当下Android使用最频繁的网络请求框架&#xff0c;由Square公司开源。Google在Android4.4以后开始将源码中 的HttpURLConnection底层实现替换为OKHttp&#xff0c;同时现在流行的Retrofit框架底层同样是使用OKHttp的。 OKHttp优点: 1、支持Http1、Http2、Quic以及Web…

MySQL多实例下安装不同的版本

MySQL多版本安装 主要步骤&#xff1a; 1. 在/etc/my.cnf 配置中&#xff0c;更改对应配置。相对于同一版本多实例需要配置的参数&#xff0c;不同版本多实例需要多配置basedir参数&#xff0c;指向mysql的解压目录。 2. 初始化数据目录。进入对应解压的MySQL目录&#xff…

Transformer理论学习

Transformer出自于论文《attention is all you need》。 一些主流的序列模型主要依赖于复杂的循环结构或者CNN&#xff0c;这里面包含了编解码器等。而Transformer主要的结构是基于注意力机制&#xff0c;而且是用多头注意力机制去替换网络中的循环或者CNN(换言之就是transfor…

一篇文章带你彻底了解Java Object类

一篇文章带你彻底了解Java Object类 ​ 在Java的世界中&#xff0c;有一个神秘的存在&#xff0c;它是所有类的根基&#xff0c;无所不在&#xff0c;无所不知。它就是——Object类。本文将带你深入探索Java中这个神秘之源&#xff0c;解密Object类的奥秘&#xff0c;让你更好…

粒子群算法运行时间太长怎么办?—教你一招降低94%的运行时间

不管是初学者还是精通智能优化算法(粒子群算法&#xff0c;遗传算法等)的朋友&#xff0c;相信你们都对智能优化算法运行之慢深有体会&#xff0c;对于比较复杂的问题&#xff0c;经常出现运行一次几小时&#xff0c;调试一次几小时的情况。调试了这么多年代码&#xff0c;智能…

数仓架构模型设计参考

1、数据技术架构 1.1、技术架构 1.2、数据分层 将数据仓库分为三层&#xff0c;自下而上为&#xff1a;数据引入层&#xff08;ODS&#xff0c;Operation Data Store&#xff09;、数据公共层&#xff08;CDM&#xff0c;Common Data Model&#xff09;和数据应用层&#xff…

IoTDB原理剖析

一、介绍 IoTDB&#xff08;物联网数据库&#xff09;是一体化收集、存储、管理与分析物联网时序数据的软件系统。 Apache IoTDB采用轻量式架构&#xff0c;具有高性能和丰富的功能。 IoTDB从存储上对时间序列进行排序&#xff0c;索引和chunk块存储&#xff0c;大大的提升时序…

wireshark 安装和使用

wireshark&#xff0c;世界上最受欢迎的网络协议分析器。是一个网络流量分析器&#xff0c;或“嗅探器”&#xff0c;适用于Linux、macOS、*BSD和其他Unix和类Unix操作系统以及Windows。它使用图形用户界面库Qt以及libpcap和npcap作为数据包捕获和过滤库。 wireshark&#xff…

MyBatis 缓存机制复习及项目中的应用经历

背景 想起前两年工作中因为二级缓存默认开启导致的问题&#xff0c;完整的看了一个介绍 MyBatis 缓存机制的视频《MyBatis 缓存基础知识讲解》。 总计知识点&#xff1a; 缓存的类型及开关这是个形同虚设的功能&#xff0c;线上环境应该禁用缓存 MyBatis 缓存分类 MyBasit…

AWD攻防学习总结(草稿状态,待陆续补充)

AWD攻防学习总结 防守端1、修改密码2、备份网站3、备份数据库4、部署WAF5、部署文件监控脚本6、部署流量监控脚本/工具7、D盾扫描&#xff0c;删除预留webshell8、代码审计&#xff0c;seay/fortify扫描&#xff0c;漏洞修复及利用9、时刻关注流量和积分信息&#xff0c;掉分时…

yolov2检测网数据集标注_labelme使用_json2txt格式转换

yolov2检测网数据集标注_labelme使用_json2txt格式转换 一、安装Anaconda二、创建labelme虚拟环境三、使用labelme标注健康非健康猫狗数据3.1 打开数据集所在文件夹3.2 进行标注数据集3.3 json2txt3.4 按文件目录和训练测试数据集重分配 四、数据喂给服务器网络参考链接 一、安…

容器安装Nginx

文章目录 容器安装nginx下载安装容器1、安装docker容器2、安装nginx3、容器运行nginx结果 容器安装nginx 下载安装容器 1、安装docker容器 yum makecache fast # 更新yum缓存 yum-config-manager \--add-repo \http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.…

Rookit系列一 【隐藏网络端口】【支持Win7 x32/x64 ~ Win10 x32/x64】

文章目录 Rookit系列一 【隐藏网络端口】【支持Win7 x32/x64 ~ Win10 x32/x64】前言探究隐藏网络端口netstat分析隐藏网络端口的原理关键数据结构隐藏网络端口源码 效果演示 Rookit系列一 【隐藏网络端口】【支持Win7 x32/x64 ~ Win10 x32/x64】 前言 Rookit是个老生常谈的话…