0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Golang根据job数量动态控制每秒协程的最大创建数量方法简析

马哥Linux运维 来源:稀土掘金 2023-12-24 14:21 次阅读

需求:第三方的接口,限制接口请求的QPS,每秒5次

需要控制job「访问接口」的次数,每秒不能同时超过5次,包括 进行中的任务、刚启动的任务

要确保单位时间内(例如每秒)运行的任务数量不超过特定的上限(如5个任务),并且在任务执行完成得很快时,考虑已完成的任务和正在执行的任务作为正在运行的任务总数,可以使用限流器来控制任务的启动频率,并结合使用信号量来管理同时运行的任务数量。

具体来说,使用一个信号量来限制同时进行的任务数量,并且在任务完成时,仅在下一秒钟允许新的任务开始,以确保即使某些任务快速完成,也不会在同一秒钟内启动超过限制数量的任务

package main


import (
    "context"
    "fmt"
    "math/rand"
    "sync"
    "sync/atomic"
    "time"


    "golang.org/x/time/rate"
)


func RateLimit() {
    const maxJobsPerSecond = 5
    const numJobs = 22
    var wg sync.WaitGroup


    // 计数器
    var runningJobs int32 // 当前正在执行的任务数量
    var startedJobs int32 // 启动后的任务数量
    var finishedJobs int32 // 刚完成的任务数量


    limiter := rate.NewLimiter(rate.Every(time.Second/time.Duration(maxJobsPerSecond)), maxJobsPerSecond)
    semaphore := make(chan struct{}, maxJobsPerSecond)


    for i := 1; i <= numJobs; i++ {
        wg.Add(1)
        go func(jobID int) {
            defer wg.Done()
            limiter.Wait(context.Background()) // 等待限流器允许进行下一个任务


            semaphore <- struct{}{} // 获取信号量
            atomic.AddInt32(&startedJobs, 1)
            atomic.AddInt32(&runningJobs, 1)


            executeJob(jobID) // 执行任务
            atomic.AddInt32(&finishedJobs, 1)
            atomic.AddInt32(&runningJobs, -1)


            <-time.After(time.Second) // 等待一秒钟后释放信号量
            <-semaphore


            // 打印当前状态
            printStatus(&runningJobs, &startedJobs, &finishedJobs)
        }(i)
    }


    wg.Wait()
    fmt.Println("所有工作完成")
}

注意事项

限流器rate.NewLimiter用于控制任务启动的频率,以确保每秒不超过maxJobsPerSecond个任务开始执行。

使用信号量semaphore来控制同时进行的任务数量。

为了确保在任何一秒内同时进行的任务数量不超过限制,在任务完成后等待一秒钟,然后再释放信号量。这样做可以保证即使任务很快完成,也不会立即启动新的任务。

这种实现方式确保了即使任务执行得很快,每秒钟启动的新任务数量也不会超过限制,并且同时考虑了正在执行和刚刚完成的任务。

动态创建协程

协程的启动是动态的。在代码中,每个任务对应于一个动态创建的协程。这些协程是在循环中根据任务数量(numJobs)动态生成的。

具体来说,每当有一个新的任务需要执行时,都会创建一个新的协程来处理这个任务。这是通过在main函数的循环中调用go关键字实现的。这个过程在每次循环迭代中发生,从而为每个任务动态创建一个新的协程

由于使用了限流器(rate.Limiter),这些协程不是一次性全部创建,而是根据限流器允许的速率逐个创建。每个协程在开始执行任务之前会等待限流器的许可,以此确保每秒启动的任务数量不超过设定的最大值

func executeJob(jobID int) {
  startTime := time.Now() // 记录任务开始时间
  
    // 模拟任务执行时间
    fmt.Printf("%v Job %d started
",time.Now().Format("2006-01-02 1505.000"), jobID)
  // 初始化随机数种子
  rand.Seed(time.Now().UnixNano())
  // 随机生成一个时间间隔(例如,1到5000毫秒之间)
  min := 1
  max := 5000
  duration := time.Duration(rand.Intn(max-min+1)+min) * time.Millisecond
  time.Sleep(duration)


  durationCost := time.Since(startTime) // 计算任务耗时


    fmt.Printf("%v Job %d finished Cost:%v
", time.Now().Format("2006-01-02 1505.000"),jobID, durationCost)
}


func printStatus(runningJobs, startedJobs, finishedJobs *int32) {
    fmt.Printf("Current status - Running: %d, Started: %d, Finished: %d
",
        atomic.LoadInt32(runningJobs),
        atomic.LoadInt32(startedJobs),
        atomic.LoadInt32(finishedJobs))
}

可以在代码中添加额外的逻辑来跟踪和打印正在执行、进行中、刚启动和刚完成的任务数量。使用原子操作(来自sync/atomic包)来确保在并发环境下对这些计数器的操作是安全的。

在这个示例中:

使用sync/atomic包中的AddInt32和LoadInt32来安全地增加和读取计数器的值。

在每个任务开始时,增加startedJobs和runningJobs计数器。

在每个任务完成时,增加finishedJobs计数器,并减少runningJobs计数器。

在任务完成后和释放信号量前,打印当前的任务状态。

注意事项

这种方法可以帮助我们跟踪不同状态下的任务数量。

使用原子操作确保在并发环境中对计数器的读写是安全的。

printStatus函数在每个任务的结束时被调用,以打印当前的任务状态

链接:https://juejin.cn/post/7315314479204696079








审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 限流器
    +关注

    关注

    0

    文章

    38

    浏览量

    14422
  • QPS
    QPS
    +关注

    关注

    0

    文章

    23

    浏览量

    8748

原文标题:Golang根据job数量动态控制每秒协程的最大创建数量方法

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    电源设计:如何利用波特图来满足动态控制行为的要求

    本文介绍如何利用波特图来快速评估您的电源设计是否满足动态控制行为要求。电源通常通过控制环路保持固定的输出电压。
    发表于 03-14 10:54 1018次阅读
    电源设计:如何利用波特图来满足<b class='flag-5'>动态控制</b>行为的要求

    采用COT稳压器动态控制输出电压

    输入来达到这一任务目的,但是大多数宽泛 VIN 转换器都不提供。在这篇博客文章中,我将讨论一种通过反馈引脚动态控制 DC/DC 转换器输出电压的通用方法。COT 转换器非常适合可变输出电压应用,因为
    发表于 09-19 11:01

    统计广告数量的可靠方法是什么?

    检查。是否有可靠的方法来计算固件中的广告数量,因为调用CyByLyGAPStPad广告(CyByLuffAdjSuxFixFor)直到超时
    发表于 10-30 09:36

    什么是多任务系统?FreeRTOS任务与

    功能,初学者必须先掌握——任务的创建、删除、挂起和恢复等操作。本章节分为如下几部分:*什么是多任务系统*FreeRTOS任务与*初次使用*任务状态*任务优先级*任务实现*任务控制
    发表于 02-18 06:38

    如何最大限度减小电源设计中输出电容的数量和尺寸?

    电源输出电容一般是100 nF至100 μF的陶瓷电容,它们耗费资金,占用空间,而且,在遇到交付瓶颈的时候还会难以获得。所以,如何最大限度减小输出电容的数量和尺寸,这个问题反复被提及。 输出电容造成
    发表于 03-21 14:42

    如何最大限度减小电源设计中输出电容的数量和尺寸

    电源输出电容一般是100 nF至100 μF的陶瓷电容,它们耗费资金,占用空间,而且,在遇到交付瓶颈的时候还会难以获得。所以,如何最大限度减小输出电容的数量和尺寸,这个问题反复被提及。输出电容造成
    发表于 06-14 10:19

    一种通过反馈引脚动态控制DC/DC转换器输出电压的通用方法

    都不提供。在这篇博客文章中,我将讨论一种通过反馈引脚动态控制 DC/DC 转换器输出电压的通用方法。COT 转换器非常适合可变输出电压应用,因为输出电压变化不会影响转换器的闭环稳定性。支持动态输出电压
    发表于 11-23 07:44

    基于多步预测性能指标函数的神经网络逆动态控制方法

    神经网络逆动态控制作为神经网络控制领域中一种重要的控制方法,通过建立对象的逆动态模型从而实现对象输出完全跟踪给定输入的理想
    发表于 12-20 15:15 2次下载

    基于多步预测性能指标函数的神经网络逆动态控制方法

    针对一些复杂的非线性系统在神经网络逆动态控制方法控制效果不理想的问题,本文提出对被控对象进行直接多步预测,利用多步预测性能指标函数对系统实现基于神经网络的逆
    发表于 01-07 15:41 11次下载

    最大处理器数量

    最大处理器数量          
    发表于 12-17 11:03 323次阅读

    PCI插槽最大数量

    PCI插槽最大数量         
    发表于 12-26 16:09 646次阅读

    如何采用 COT 稳压器动态控制输出电压

    如何采用 COT 稳压器动态控制输出电压
    发表于 11-07 08:07 0次下载
    如何采用 COT 稳压器<b class='flag-5'>动态控制</b>输出电压

    电源设计:如何利用波特图来满足动态控制行为的要求?

    电源设计:如何利用波特图来满足动态控制行为的要求?
    的头像 发表于 10-17 15:18 281次阅读
    电源设计:如何利用波特图来满足<b class='flag-5'>动态控制</b>行为的要求?

    单片机实现炉温动态控制

    电子发烧友网站提供《单片机实现炉温动态控制.pdf》资料免费下载
    发表于 10-12 09:48 0次下载
    单片机实现炉温<b class='flag-5'>动态控制</b>

    使用动态控制七段式LED指示灯的显示应用指南

    电子发烧友网站提供《使用动态控制七段式LED指示灯的显示应用指南.pdf》资料免费下载
    发表于 01-29 10:33 0次下载
    使用<b class='flag-5'>动态控制</b>七段式LED指示灯的显示应用指南