1. 源码阅读

  • 整个包实现原理基于令牌桶算法:随时间以 1/r 个令牌的速度向容积为 b 个令牌的桶中添加令牌,有请求就取走令牌,若令牌不足则不执行请求或者等待
  • Allow 方法的调用链:lim.Allow() bool → lim.AllowN(time.Now(), 1) → lim.reserveN(now, n, 0).ok,因此 reserveN 方法的实现很关键
// Allow is shorthand for AllowN(time.Now(), 1).
func (lim *Limiter) Allow() bool {
return lim.AllowN(time.Now(), )
} // AllowN reports whether n events may happen at time now.
// Use this method if you intend to drop / skip events that exceed the rate limit.
// Otherwise use Reserve or Wait.
func (lim *Limiter) AllowN(now time.Time, n int) bool {
return lim.reserveN(now, n, ).ok
}
  • reserveN 方法是线程安全的,通过互斥锁锁住判断操作:

lim.mu.Lock()
......
lim.mu.Unlock()
return r
  • reserveN 方法,首先检查限制为 Inf,不需要判断直接返回 true:

if lim.limit == Inf {
lim.mu.Unlock()
return Reservation{
ok: true,
lim: lim,
tokens: n,
timeToAct: now,
}
}
  • 时间和令牌的计算是根据单位时间内的限制数量和剩余令牌数所占比例计算的:
// durationFromTokens is a unit conversion function from the number of tokens to the duration
// of time it takes to accumulate them at a rate of limit tokens per second.
func (limit Limit) durationFromTokens(tokens float64) time.Duration {
seconds := tokens / float64(limit)
return time.Nanosecond * time.Duration(1e9*seconds)
} // tokensFromDuration is a unit conversion function from a time duration to the number of tokens
// which could be accumulated during that duration at a rate of limit tokens per second.
func (limit Limit) tokensFromDuration(d time.Duration) float64 {
return d.Seconds() * float64(limit)
}
  • 根据令牌数限制和当前存在的令牌数计算还有上次更新至今的时间差计算可以补充多少令牌:
// Avoid making delta overflow below when last is very old.
maxElapsed := lim.limit.durationFromTokens(float64(lim.burst) - lim.tokens)
elapsed := now.Sub(last)
if elapsed > maxElapsed {
elapsed = maxElapsed
} // Calculate the new number of tokens, due to time that passed.
delta := lim.limit.tokensFromDuration(elapsed)
tokens := lim.tokens + delta
if burst := float64(lim.burst); tokens > burst {
tokens = burst
}
  • 更新补充后的当前令牌数减去请求的令牌数,如果不足,根据不足的令牌数计算需要等待的时间:
// Calculate the remaining number of tokens resulting from the request.
tokens -= float64(n)
fmt.Printf("WangAo test: After sub n: tokens: %v\n", tokens) // Calculate the wait duration
var waitDuration time.Duration
if tokens < {
waitDuration = lim.limit.durationFromTokens(-tokens)
}
  • 根据请求数量和等待时间判断是否允许请求:
// Decide result
ok := n <= lim.burst && waitDuration <= maxFutureReserve

3. 参考文献

Golang(七)golang.org/x/time/rate 实现频率限制的更多相关文章

  1. 【GoLang】GoLang map 非线程安全 & 并发度写优化

    Catena (时序存储引擎)中有一个函数的实现备受争议,它从 map 中根据指定的 name 获取一个 metricSource.每一次插入操作都会至少调用一次这个函数,现实场景中该函数调用更是频繁 ...

  2. 【GoLang】golang HTTP GET/POST JSON的服务端、客户端示例,包含序列化、反序列化

    服务端代码示例: package main import ( "encoding/json" "fmt" "io/ioutil" " ...

  3. 【GoLang】golang垃圾回收 & 性能调优

    golang垃圾回收 & 性能调优 参考资料: 如何监控 golang 程序的垃圾回收_Go语言_第七城市 golang的垃圾回收(GC)机制 - 两只羊的博客 - 博客频道 - CSDN.N ...

  4. 【GoLang】golang 最佳实践汇总

    最佳实践 1 包管理 1.1 使用包管理对Golang项目进行管理,如:godep/vendor等工具 1.2 main/init函数使用,init函数参考python 1.2.1 main-> ...

  5. 【GoLang】golang 的精髓--流水线,对现实世界的完美模拟

    直接上代码: package main import ( "fmt" "runtime" "strconv" "sync" ...

  6. 【GoLang】golang 中 defer 参数的蹊跷

    参考资料: http://studygolang.com/articles/7994--Defer函数调用参数的求值 golang的闭包和普通函数调用区别:http://studygolang.com ...

  7. 【GoLang】golang context channel 详解

    代码示例: package main import ( "fmt" "time" "golang.org/x/net/context" ) ...

  8. 【GoLang】golang 交叉编译 实现&工具

    apt-get install gcc-mingw-w64 env CGO_ENABLED= GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc g ...

  9. 【GoLang】golang底层数据类型实现原理

    虽然golang是用C实现的,并且被称为下一代的C语言,但是golang跟C的差别还是很大的.它定义了一套很丰富的数据类型及数据结构,这些类型和结构或者是直接映射为C的数据类型,或者是用C struc ...

随机推荐

  1. [转] console.log的高级用法

    //基本用法 console.log('最常见用法\n换行'); console.error('输出错误信息 会以红色显示'); console.warn('打印警告信息 会以黄色显示'); cons ...

  2. nginx 配置反向代理,负载均衡实战解析

    前言:NGINX的反向代理和负载均衡是网站架构中经常用到的一种高并发,高可用的方案,下面我们直接实战操作,当然理论也是要的. 一.反向代理 过程:反向代理:客户端 一>代理 <一> ...

  3. WPF 精修篇 BackgroundWorker

    原文:WPF 精修篇 BackgroundWorker 效果 <Grid> <Grid.RowDefinitions> <RowDefinition Height=&qu ...

  4. JAVA集合框架的特点及实现原理简介

    1.集合框架总体架构 集合大致分为Set.List.Queue.Map四种体系,其中List,Set,Queue继承自Collection接口,Map为独立接口 Set的实现类有:HashSet,Li ...

  5. 【转】LockSupport深入浅出

    原文:https://www.cnblogs.com/qingquanzi/p/8228422.html 本篇是<自己动手写把"锁">系列技术铺垫的最后一个知识点.本篇 ...

  6. iOS 原生推送(APNS)的实现

    1.前期准备工作 创建你的APNs keys 或者 创建推送证书,这两个创建一个即可实现推送.这两个创建一个即可实现推送.这两个创建一个即可实现推送.重要的事情说三遍,我看评论区有小伙伴误解. 1.  ...

  7. FFmpeg基础一

    来源:http://blog.csdn.net/chance_yin/article/details/10323441 一.研究数字多媒体,首先要了解几个基本术语(ffmpeg的相关文档几乎都是英文的 ...

  8. 源码升级SUSE openssh

    1.check old opensslrpm -q opensslopenssl versionwhich opensslwhereis opensslls /etc/ssl 2.backup old ...

  9. Linux的DNS实现负载均衡及泛域名部署

    DNS负载均衡技术的实现原理是在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到 ...

  10. 二十、Python与Mysql交互

    先安装一个python与MySQL交互的包:MySQL-python $ gunzip MySQL-python-1.2.2.tar.gz $ tar -xvf MySQL-python-1.2.2. ...