当前位置: 首页 > news >正文

Go 控制协程(goroutine)的并发数量

在使用协程并发处理某些任务时, 其并发数量往往因为各种因素的限制不能无限的增大. 例如网络请求、数据库查询等等。

从运行效率角度考虑,在相关服务可以负载的前提下(限制最大并发数),尽可能高的并发。

在Go语言中,可以使用一些方法来控制协程(goroutine)的并发数量,以防止并发过多导致资源耗尽或性能下降

1、使用信号量(Semaphore)

可以使用 Go 语言中的 channel 来实现简单的信号量,限制并发数量

package mainimport ("fmt""sync"
)func worker(id int, sem chan struct{}) {sem <- struct{}{} // 占用一个信号量defer func() {<-sem // 方法运行结束释放信号量}()// 执行工作任务fmt.Printf("Worker %d: Working...\n", id)
}func main() {concurrency := 3sem := make(chan struct{}, concurrency)var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(id int) {defer wg.Done()worker(id, sem)}(i)}wg.Wait()close(sem)
}

sem 是一个有缓冲的 channel,通过控制 channel 中元素的数量,实现了一个简单的信号量机制 

 2、使用协程池

可以创建一个固定数量的协程池,将任务分发给这些协程执行。 

package mainimport ("fmt""sync"
)func worker(id int, jobs <-chan int, results chan<- int) {//jobs等待主要协程往jobs放数据for j := range jobs {fmt.Printf("协程池 %d: 协程池正在工作 %d\n", id, j)results <- j}
}func main() {const numJobs = 5    //协程要做的工作数量const numWorkers = 3 //协程池数量jobs := make(chan int, numJobs)results := make(chan int, numJobs)var wg sync.WaitGroup// 启动协程池for i := 1; i <= numWorkers; i++ {wg.Add(1)go func(id int) {defer wg.Done()worker(id, jobs, results)}(i)}// 提交任务for j := 1; j <= numJobs; j++ {jobs <- j}close(jobs)// 等待所有工作完成go func() {wg.Wait()close(results)}()// 处理结果for result := range results {fmt.Println("Result:", result)}
}

jobs 通道用于存储任务,results 通道用于存储处理结果。通过创建固定数量的工作协程,可以有效地控制并发数量。

3、使用其他包

Go 1.16 引入了 golang.org/x/sync/semaphore 包,它提供了一个更为灵活的信号量实现。

案例一

限制对外部API的并发请求 

假设我们有一个外部API,它对并发请求有限制,我们希望确保不超过这个限制。我们可以使用semaphore.Weighted来控制对API的并发访问

package mainimport ("context""fmt""golang.org/x/sync/semaphore""sync""time"
)func main() {/*1、在并发量一定的情况下,通过改变允许并发请求数可以更快处理请求任务(在CPU够用的前提下)2、sem := semaphore.NewWeighted(n),参数n就是权重量3、当一个协程需要获取的单位的权重越多,运行就会慢(比如权重总量n=5个,一个协程分配了2个,跟一个协程分配1个效率是不一样的)4、信号量没有足够的可用权重的情况发生在所有已分配的权重单位都已经被占用,即信号量的当前权重计数达到了它的总容量。在这种情况下,任何尝试通过Acquire方法获取更多权重的调用都将无法立即完成,从而导致调用者(通常是goroutine)阻塞,直到其他调用者释放一些权重单位。*//*1、权权重较大的任务在资源竞争时有更高的优先级,更容易获得执行的机会2、如果当前资源足够满足高权重任务的需求,这些任务将立即执行;若资源不足,则按照权重高低顺序排队等待3、一旦任务开始执行,其完成的速度主要取决于任务自身的逻辑复杂度、所需资源以及系统的当前负载等因素,与任务在信号量中的权重无关3、高权重的任务并不会中断已经在执行的低权重任务,而是等待这些任务自行释放资源。一旦资源释放,等待队列中的高权重任务将优先被唤醒4、Acquire 方法会检查当前信号量的可用资源量是否满足请求的权重,如果满足,则立即减少信号量的资源计数并返回,允许任务继续执行。如果不满足,任务将阻塞等待,直到有足够的资源被释放*/// 记录开始时间startTime := time.Now()// 假设外部API允许的最大并发请求为5(信号量的总容量是5个权重单位)const (maxConcurrentRequests = 5)sem := semaphore.NewWeighted(maxConcurrentRequests)var wg sync.WaitGroup// 模拟对外部API的10个并发请求for i := 0; i < 10; i++ {wg.Add(1)go func(requestId int) {defer wg.Done()// 假设我们想要获取2个单位的权重if err := sem.Acquire(context.Background(), 2); err != nil {fmt.Printf("请求 %d 无法获取信号量: %v\n", requestId, err)return}defer sem.Release(2) // 请求完成后释放信号量// 模拟对API的请求处理fmt.Printf("请求 %d 开始...\n", requestId)time.Sleep(2 * time.Second) // 模拟网络延迟fmt.Printf("请求 %d 完成。\n", requestId)}(i)}wg.Wait()// 记录结束时间endTime := time.Now()// 计算并打印总耗时fmt.Printf("程序总耗时: %v\n", endTime.Sub(startTime))
}

信号量没有足够的可用权重的情况发生在所有已分配的权重单位都已经被占用,即信号量的当前权重计数达到了它的总容量。在这种情况下,任何尝试通过Acquire方法获取更多权重的调用都将无法立即完成,从而导致调用者(通常是goroutine)阻塞,直到其他调用者释放一些权重单位。

以下是一些导致信号量没有足够可用权重的具体情况:

  1. 信号量初始化容量较小:如果信号量的总容量设置得较小,而并发请求的数量较大,那么很快就会出现权重不足的情况。

  2. 长时间占用权重:如果某些goroutine长时间占用权重单位而不释放,这会导致其他goroutine无法获取到权重,即使这些goroutine只是少数。

  3. 权重分配不均:在某些情况下,可能存在一些goroutine占用了不成比例的权重单位,导致其他goroutine无法获取足够的权重。

  4. 权重释放不及时:如果goroutine因为错误或异常情况提前退出,而没有正确释放它们所占用的权重,那么这些权重单位将不会被回收到信号量中。

  5. 高频率的请求:在短时间内有大量goroutine请求权重,即使它们请求的权重不大,累积起来也可能超过信号量的总容量。

  6. 信号量权重未正确管理:如果信号量的权重管理逻辑存在缺陷,例如错误地释放了过多的权重,或者在错误的时间点释放权重,也可能导致可用权重不足。

为了避免信号量没有足够的可用权重,可以采取以下措施:

  • 合理设置信号量容量:根据资源限制和并发需求合理设置信号量的总容量。
  • 及时释放权重:确保在goroutine完成工作后及时释放权重。
  • 使用超时:在Acquire调用中使用超时,避免无限期地等待权重。
  • 监控和日志记录:监控信号量的使用情况,并记录关键信息,以便及时发现和解决问题。
  • 权重分配策略:设计合理的权重分配策略,确保权重的公平和高效分配。

通过这些措施,可以更好地管理信号量的使用,避免因权重不足导致的并发问题。

案例二

假设有一个在线视频平台,它需要处理不同分辨率的视频转码任务。由于高清视频转码比标清视频更消耗计算资源,因此平台希望设计一个系统,能够优先处理更多标清视频转码请求,同时又不完全阻塞高清视频的转码,以保持整体服务质量和资源的有效利用。

package mainimport ("fmt""golang.org/x/net/context""golang.org/x/sync/semaphore""runtime""sync""time"
)// VideoTranscodeJob 视频转码任务
type VideoTranscodeJob struct {resolution stringweight     int64
}func main() {cpuCount := runtime.NumCPU()fmt.Printf("当前CPU个数%v\n", cpuCount)/*1、权权重较大的任务在资源竞争时有更高的优先级,更容易获得执行的机会2、如果当前资源足够满足高权重任务的需求,这些任务将立即执行;若资源不足,则按照权重高低顺序排队等待3、一旦任务开始执行,其完成的速度主要取决于任务自身的逻辑复杂度、所需资源以及系统的当前负载等因素,与任务在信号量中的权重无关3、高权重的任务并不会中断已经在执行的低权重任务,而是等待这些任务自行释放资源。一旦资源释放,等待队列中的高权重任务将优先被唤醒4、Acquire 方法会检查当前信号量的可用资源量是否满足请求的权重,如果满足,则立即减少信号量的资源计数并返回,允许任务继续执行。如果不满足,任务将阻塞等待,直到有足够的资源被释放*/// 初始化两个信号量,一个用于标清,一个用于高清,假设总共有8个CPU核心可用normalSem := semaphore.NewWeighted(6)  // 标清任务,分配6个单位权重,因为它们消耗资源较少highDefSem := semaphore.NewWeighted(2) // 高清任务,分配2个单位权重,因为它们更消耗资源var wg sync.WaitGroup//假设有20个需要转码的视频videoJobs := []VideoTranscodeJob{{"HD", 2}, {"HD", 2}, {"SD", 1}, {"SD", 1}, {"HD", 2},{"SD", 1}, {"SD", 1}, {"HD", 2}, {"SD", 1}, {"HD", 2},{"SD", 4}, {"SD", 4}, {"HD", 2}, {"SD", 1}, {"HD", 2},{"SD", 1}, {"SD", 4}, {"HD", 2}, {"SD", 6}, {"HD", 2},}for _, job := range videoJobs {wg.Add(1)go func(job VideoTranscodeJob) {defer wg.Done()var sem *semaphore.Weightedswitch job.resolution {case "SD":sem = normalSem //分配权重大,当前为6,任务在获取执行机会上有优势,但并不直接意味着执行速度快case "HD":sem = highDefSemdefault:panic("无效的分辨率")}if err := sem.Acquire(context.Background(), job.weight); err != nil {fmt.Printf("名为 %s 视频无法获取信号量: %v\n", job.resolution, err)return}defer sem.Release(job.weight) //释放权重对应的信号量// 模拟转码任务执行fmt.Printf("转码 %s 视频 (权重: %d)...\n", job.resolution, job.weight)//通过利用VideoTranscodeJob的weight值来模拟转码时间的长短,HD用时长则设置2比SD的1大,*时间就自然长,运行就时间长time.Sleep(time.Duration(job.weight*100) * time.Millisecond) // 模拟不同分辨率视频转码所需时间fmt.Printf("------------------------%s 视频转码完成。。。\n", job.resolution)}(job)}wg.Wait()
}

标清(SD)和高清(HD),分别分配了不同的权重(1和2)。通过创建两个不同权重的信号量,我们可以控制不同类型任务的同时执行数量,从而优先保证标清视频的快速处理,同时也确保高清视频能够在不影响系统稳定性的情况下进行转码。这展示了带权重的并发控制如何帮助在资源有限的情况下优化任务调度和执行效率。

 注意:对协程分配的权重单位数不能大于对应上下文semaphore.NewWeighted(n)中参数n的单位数

案例三

package mainimport ("context""fmt""sync""time""golang.org/x/sync/semaphore"
)type weightedTask struct {id     intweight int64
}func main() {const (maxTotalWeight = 20 // 最大总权重)sem := semaphore.NewWeighted(maxTotalWeight)var wg sync.WaitGrouptasksCh := make(chan weightedTask, 10)// 发送任务for i := 1; i <= 10; i++ {tasksCh <- weightedTask{id: i, weight: int64(i)} // 假设任务ID即为其权重}close(tasksCh)// 启动任务处理器for task := range tasksCh {wg.Add(1)go func(task weightedTask) {defer wg.Done()if err := sem.Acquire(context.Background(), int64(task.id)); err != nil {fmt.Printf("任务 %d 无法获取信号量: %v\n", task.id, err)return}defer sem.Release(int64(task.id)) //释放// 模拟任务执行fmt.Printf("任务 %d (权重: %d) 正在运行...\n", task.id, task.weight)time.Sleep(time.Duration(task.weight*100) * time.Millisecond) // 示例中简单用时间模拟权重影响fmt.Printf("任务 %d 完成.\n", task.id)}(task)}wg.Wait()
}

 

总结

选择哪种方法取决于具体的应用场景和需求。使用信号量是一种简单而灵活的方法,而协程池则更适用于需要批量处理任务的情况。golang.org/x/sync/semaphore 包提供了一个标准库外的更灵活的信号量实现         

相关文章:

Go 控制协程(goroutine)的并发数量

在使用协程并发处理某些任务时, 其并发数量往往因为各种因素的限制不能无限的增大. 例如网络请求、数据库查询等等。 从运行效率角度考虑&#xff0c;在相关服务可以负载的前提下&#xff08;限制最大并发数&#xff09;&#xff0c;尽可能高的并发。 在Go语言中&#xff0c;…...

web安全渗透测试十大常规项(一):web渗透测试之CSRF跨站请求伪造

渗透测试之CSRF跨站请求伪造 CSRF跨站请求伪造 CSRF跨站请求伪造...

YOLOv10尝鲜测试五分钟极简配置

最近清华大学团队又推出YOLOv10&#xff0c;真是好家伙了。 安装&#xff1a; pip install supervision githttps://github.com/THU-MIG/yolov10.git下载权重&#xff1a;https://github.com/THU-MIG/yolov10/releases/download/v1.0/yolov10n.pt 预测&#xff1a; from ult…...

社交媒体数据恢复:聊天宝

请注意&#xff0c;本教程仅针对聊天宝应用程序&#xff0c;而非其他聊天软件。以下是详细的步骤&#xff1a; 首先&#xff0c;请确保您已经登录了聊天宝应用程序。如果您尚未登录&#xff0c;请使用您的账号登录。 在聊天宝主界面&#xff0c;找到您希望恢复聊天记录的对话框…...

备战秋招—模拟版图面试题来了

随着暑期的脚步逐渐临近&#xff0c;电子工程和集成电路设计领域的毕业生们&#xff0c;也将迎来了另一个求职的黄金期——秋招。我们总说机会是留给有准备的人。对于有志于投身于模拟版图设计的学子们来说&#xff0c;为了在众多求职者中脱颖而出&#xff0c;充分备战模拟版图…...

CAN总线简介

1. CAN总线概述 1.1 CAN定义与历史背景 CAN&#xff0c;全称为Controller Area Network&#xff0c;是一种基于消息广播的串行通信协议。它最初由德国Bosch公司在1983年为汽车行业开发&#xff0c;目的是实现汽车内部电子控制单元&#xff08;ECUs&#xff09;之间的可靠通信。…...

【HSQL001】HiveSQL内置函数手册总结(更新中)

1.熟悉、梳理、总结下Hive SQL相关知识体系。 2.日常研发过程中使用较少&#xff0c;随着时间的推移&#xff0c;很快就忘得一干二净&#xff0c;所以梳理总结下&#xff0c;以备日常使用参考 3.欢迎批评指正&#xff0c;跪谢一键三连&#xff01; 文章目录 1.函数清单 1.函数清…...

Rust面试宝典第14题:旋转数组

题目 给定一个数组&#xff0c;将数组中的元素向右移动k个位置&#xff0c;其中k是非负数。要求如下&#xff1a; &#xff08;1&#xff09;尽可能想出更多的解决方案&#xff0c;至少有三种不同的方法可以解决这个问题。 &#xff08;2&#xff09;使用时间复杂度为O(n)和空间…...

解决SpringBoot中插入汉字变成?(一秒解决)

在这里url后面加一行配置即可&useUnicodetrue&characterEncodingUTF-8即可 解释 spring.datasource.url: 这里包含了数据库的URL&#xff0c;以及额外的参数如useUnicodetrue用于启用Unicode字符集支持&#xff0c;characterEncodingUTF-8用于指定字符编码为UTF-8&…...

5.26牛客循环结构

1002. 难点&#xff1a; 两层循环条件设置 思路 可以设置三个变量 代码 1003 思路&#xff1a; 与星号双塔差不多&#xff0c;在此基础上加大一点难度 每日练题5.23 &#xff08;EOF用法&#xff09;-CSDN博客 代码 1004 代码...

AIGC 004-T2I-adapter另外一种支持多条件组合控制的文生图方案!

AIGC 004-T2I-adapter另外一种支持多条件组合控制的文生图方案&#xff01; 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 T2I-Adapter 论文提出了一种名为 T2I-Adapter 的轻量级适配器模块&#xff0c;旨在增强文本到图像 (T2I) 扩散模型的语义理解和生成能力。 论文指出…...

详解 Cookies 和 WebStorage

Cookies 和 WebStorage Cookies 和 WebStorageCookies简要介绍操作 Cookies&#xff08;document.cookie&#xff09;不足之处 WebStorage简要介绍LocalStorage Vs. SessionStorage操作 WebStorage 三种数据存储方式的对比分析共性差异 REFERENCES Cookies 和 WebStorage Cook…...

BeanFactory、FactroyBean、ApplicationContext

BeanFactory Ioc容器、定义接口规范来管理spring bean的生命周期、依赖、注入&#xff0c;spring中有各种Ioc容器 FactroyBean 定制的工厂Bean&#xff0c;可以通过抽象工厂方式创建的bean&#xff0c;不纳入spring的生命周期、依赖、注入特性&#xff0c;相当于spring给第三…...

【计算机网络】HTTPS 协议原理

加密 1. 加密概念 加密就是把明文 (要传输的信息)进行一系列变换&#xff0c;生成密文。 解密就是把密文再进行一系列变换&#xff0c;还原成明文。 在这个加密和解密的过程中&#xff0c;往往需要⼀个或者多个中间的数据&#xff0c;辅助进行这个过程&#xff0c;这样的数…...

springboot + Vue前后端项目(第十二记)

项目实战第十二记 1.写在前面2. 整合Echarts2.1 vue安装Echarts2.2 使用Echarts2.3 EchartsController编写2.4 Home.vue编写 总结写在最后 1.写在前面 本篇主要讲解系统整合Echarts 2. 整合Echarts 2.1 vue安装Echarts npm i echarts -S2.2 使用Echarts vue中使用echarts的…...

linux 常用命令:find grep ps netstat sudo df du rm

rm 命令 删除 -r 是递归参数&#xff08;recursive&#xff09;&#xff0c;用于删除目录及其内容。如果不加这个参数&#xff0c;rm 命令无法删除非空目录。-f 是强制参数&#xff08;force&#xff09;&#xff0c;用于强制删除文件或目录&#xff0c;不会进行任何确认提示…...

SQLiteOpenHelper数据库帮助器

SQLiteOpenHelper数据库帮助器是Android提供的数据库辅助工具。 1、继承SQLiteOpenHelper类&#xff0c;需要重写onCreate和onUpgrade两个方法 案例&#xff1a;实现增删改查 package com.example.databases_text;import android.app.PictureInPictureParams; import androi…...

2024年5月26日 (周日) 叶子游戏新闻

资深开发者&#xff1a;3A游戏当前处于一种尴尬的中间地带游戏行业整体&#xff0c;尤其是3A游戏正处于艰难时期。尽管2023年3A游戏佳作频出&#xff0c;广受好评&#xff0c;但居高不下的游戏开发成本&#xff08;传闻《漫威蜘蛛侠2》的制作成本高达3亿美元&#xff09;正严重…...

STM32-10-定时器

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG 文章目录 一、STM32 基础定时器1. 基本定时器简介2. 基本定时器框图3. 基本定时器相关寄存器4. 定时器溢出…...

今天说的什么好呢

先这样吧...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...