• Golang限制函数调用次数


    Golang限制函数调用次数

    项目环境

    • ubuntu+go1.14

    需求描述

    • 限制某个函数5秒内只能调用一次,5秒内的其他调用抛弃

    工具包使用

    这里用到了官方限流器/time/rate

    该限流器是基于Token Bucket(令牌桶)实现的。

    简单来说,令牌桶就是一个固定大小的桶,系统会以恒定速率向桶中放Token,桶满则暂时不放。
    而用户则从桶中取Token,如果有剩余Token就可以一直取。如果没有剩余Token,则需要等到系统中被放置了Token才行。

    方法简介:

    NewLimiter

    func NewLimiter(r Limit, b int) *Limiter
    

    这里有两个参数:

    • 第一个参数是r Limit。代表每秒可以向Token桶中产生多少token。Limit实际上是float64的别名。

    • 第二个参数是b int。b代表Token桶的容量大小。

    除了直接指定每秒产生的Token个数外,还可以用Every方法来指定向Token桶中放置Token的间隔

    例如我的需求是5秒只能访问一次,那我就5秒放一个Token,桶中最多保存1个:

    var r = rate.Every( 5 * time.Second)
    var limiter = NewLimiter(limit, 1);
    

    Wait/WaitN

    func (lim *Limiter) Wait(ctx context.Context) (err error)
    func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)
    

    Wait是WaitN(ctx,1)的简写。

    当使用Wait方法消费Token时,如果此时桶内Token数组不足(小于N),那么Wait方法将会阻塞一段时间,直至Token满足条件。如果充足则直接返回。

    Wait方法有一个context参数,我们可以设置context的Deadline或者Timeout,来决定此次Wait的最长时间。

    Allow/AllowN

    func (lim *Limiter) Allow() bool
    func (lim *Limiter) AllowN(now time.Time, n int) bool
    

    Allow是AllowN(time.Now(),1)的简写。

    AllowN方法表示,截止到某一时刻,目前桶中数目是否至少为n个,满足则返回true,同时从桶中消费n个token。
    反之返回不消费Token,false。

    如果你需要在事件超出频率的时候丢弃或跳过事件,就使用AllowN,否则使用Reserve或Wait.

    结合我的需求,没有Token就抛弃,我用这个Allow

    if !limit.Allow() {
    	fmt.Println(" has no token")
    	return
    }else{
    	fmt.Println(" has  token")
    }
    

    Reserve/ReserveN

    func (lim *Limiter) Reserve() *Reservation
    func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation
    

    Reserve是ReserveN(time.Now(), 1)的简写。

    ReserveN 返回对象Reservation

    该对象的Delay()方法返回了需要等待的时间,必须等到等待时间之后,才能进行接下来的工作。

    如果不想等待,可以调用Cancel()方法,该方法会将Token归还。

    使用示例

    r := lim.ReserveN(time.Now(), 1)
    if !r.OK() {
      // 如果ReserveN 传入的n大于令牌池的容量b,那么返回false.
      return
    }
    time.Sleep(r.Delay())
    Act() //处理逻辑
    

    实现Demo

    package main
    
    import (
    	"fmt"
    	"golang.org/x/time/rate"
    	"time"
    )
    func main() {
    	// 模拟每500毫秒调用一次t函数
    	for{
    		t()
    		time.Sleep(time.Millisecond* 500)
    	}
    }
    
    var r = rate.Every( 5 * time.Second)
    var limit = rate.NewLimiter(r, 1)
    
    func t() {
    	if !limit.Allow() {
    		fmt.Println(" has no token")
    		return
    	}else{
    		fmt.Println(" has  token")
    	}
    }
    

    打印

    root@ubuntu14:/home/kingram/sourceCode/test# go build t4.go
    root@ubuntu14:/home/kingram/sourceCode/test# ./t4
     has  token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has  token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has no token
     has  token
    
  • 相关阅读:
    tomcat配置服务器默认访问index页面
    AJAX跨域名
    MYSQL日期格式
    java群发邮箱
    判断execl格式
    java解析excel表格数据
    json解析数据
    generatorConfig自动生成
    简单后台调用api
    Spring邮箱发送
  • 原文地址:https://www.cnblogs.com/Kingram/p/13445666.html
Copyright © 2020-2023  润新知