005_针对于go语言中速率限制的思考
在之前的go语言的速率限制这篇文章里,我们尝试了普通的速率限制,和脉冲型速率限制。其中,脉冲型速率限制是放开了限制,里面有3个请求是一次性到达,然后再按照200ms的速度限制的,之前的代码如下所示:
package main import "fmt"
import "time" func main() {
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
limiter := time.Tick(time.Millisecond * 200) for req := range requests {
<-limiter
fmt.Println("request", req, time.Now())
} burstyLimiter := make(chan time.Time, 3)
for i := 0; i < 3; i++ {
burstyLimiter <- time.Now()
} go func() {
for t := range time.Tick(time.Millisecond * 200) {
burstyLimiter <- t
}
}() burstyRequests := make(chan int, 5)
for i := 1; i <= 5; i++ {
burstyRequests <- i
}
close(burstyRequests)
for req := range burstyRequests {
<-burstyLimiter
fmt.Println("request", req, time.Now())
}
}
最终的输出是下面这样,可以看到下面那段输出的前三次输出,时间几乎没差,这是一次脉冲型速率限制:
request 1 2018-04-17 12:57:02.823975218 +0800 CST m=+0.205374957
request 2 2018-04-17 12:57:03.024067833 +0800 CST m=+0.405476106
request 3 2018-04-17 12:57:03.220187209 +0800 CST m=+0.601603847
request 4 2018-04-17 12:57:03.420175881 +0800 CST m=+0.801601050
request 5 2018-04-17 12:57:03.622105704 +0800 CST m=+1.003539485 request 1 2018-04-17 12:57:03.622191244 +0800 CST m=+1.003625029
request 2 2018-04-17 12:57:03.622210962 +0800 CST m=+1.003644748
request 3 2018-04-17 12:57:03.622223153 +0800 CST m=+1.003656939
request 4 2018-04-17 12:57:03.82356235 +0800 CST m=+1.205004724
request 5 2018-04-17 12:57:04.024178896 +0800 CST m=+1.405629826
那我们如果想实现另一种脉冲型速率限制怎么办,就是一开始,让速度变慢,然后再正常请求的,经过思考,代码改造如下:
package main import "fmt"
import "time" func main() {
k := 0
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
limiter := time.Tick(time.Millisecond * 200)
slow := time.Tick(time.Millisecond * 400) for req := range requests {
if k < 3 {
<-slow
k++
}
<-limiter
fmt.Println("request", req, time.Now())
}
}
运行结果如下,可以看到,前三次间隔是400ms,第四次又还原回来间隔200ms:
request 1 2018-04-17 17:04:50.9986303 +0800 CST m=+0.405591505
request 2 2018-04-17 17:04:51.395919457 +0800 CST m=+0.802875205
request 3 2018-04-17 17:04:51.794626945 +0800 CST m=+1.201577217
request 4 2018-04-17 17:04:51.993709916 +0800 CST m=+1.400657453
request 5 2018-04-17 17:04:52.196450634 +0800 CST m=+1.603395386
我来解释下代码逻辑。为了实现需求,我在前面又设置了一个打点器,然后增加判断,如果k小于3,就从打点器中取值,然后k自增。这样的话保证了前三次取值慢,后面的取值快。
这时候有人会问了,那例子中是总共两个打点器,一个是400ms,一个是200ms,为什么前三次不是400+200总共600ms,而是间隔只有400ms呢?
我来解释一下,因为代码运行到<-slow时候是阻塞状态,通道内没有值,是需要打点器每隔400ms把值存入slow中,才能继续运行的。而<-limiter按理说也是阻塞状态,也需要打点器传值的。但是别忘了,limiter是200ms,在slow传值之前,limiter就已经存入值了。所以在if判断语句结束以后,limiter不用等待传值,直接取就行了。这样的话,在if条件执行完后,<-limiter执行是瞬间完成的,不用等待200ms的。
以上就是go语言中速率限制的一些思考和改造,在实际工作中,应该还有更加完美的解决方案,期待将来的改进。
005_针对于go语言中速率限制的思考的更多相关文章
- C语言中如何将二维数组作为函数的参数传递
今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不 ...
- C语言中时钟编程
目录 C语言中时钟编程 1. 文章目的 2.基本概念 2.1 UTC时间 2.2 UNIX纪元时间 2.3 格林威治时间 (GMT) 3.时间转换 3.1 asctime函数 3.2 ctime函数 ...
- JAVA语言中的修饰符
JAVA语言中的修饰符 -----------------------------------------------01--------------------------------------- ...
- Java语言中的面向对象特性总结
Java语言中的面向对象特性 (总结得不错) [课前思考] 1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类? 2. 面向对象编程的特性有哪三个?它们各自又有哪些特性? 3. 你知 ...
- python语言中的编码问题
在编程的过程当中,常常会遇到莫名其妙的乱码问题.很多人选择出了问题直接在网上找答案,把别人的例子照搬过来,这是快速解决问题的一个好办法.然而,作为一个严谨求实的开发者,如果不从源头上彻底理解乱码产生的 ...
- 在C语言中利用PCRE实现正则表达式
1. PCRE简介 2. 正则表达式定义 3. PCRE正则表达式的定义 4. PCRE的函数简介 5. 使用PCRE在C语言中实现正则表达式的解析 6. PCRE函数在C语言中的使用小例子 1. P ...
- C语言中函数声明实现的位置
在学习C语言的时候我遇到了这么个事情,因为之前先学习的C#,在C#编译器中,函数的声明位置不会影响编译的结果,但是在C语言中却发生了错误 先看一段代码: #include <stdio.h> ...
- C语言中的栈和堆
原文出处<http://blog.csdn.net/xiayufeng520/article/details/45956305#t0> 栈内存由编译器分配和释放,堆内存由程序分配和释放. ...
- 在易语言中调用MS SQL SERVER数据库存储过程方法总结
Microsoft SQL SERVER 数据库存储过程,根据其输入输出数据,笼统的可以分为以下几种情况或其组合:无输入,有一个或多个输入参数,无输出,直接返回(return)一个值,通过output ...
随机推荐
- Typora上传图片设置
Typora上传图片设置 问题 使用Typora写文档时上传图片的路径默认是本地磁盘的路径,这样就导致一个问题,当写好的文档上传到blog.csdn等博客网站时,会导致图片失效无法识别的问题. 解决方 ...
- ElasticSearch 定时批量删除N天前的数据
描述: 之前我已经完成了使用ElasticSearch.kibana.filebeat.三个工具完成分布式集群收集 分布在各个ip地址上的微服务日志,这样就可以统一的在一个服务器上查看了所有的微服务产 ...
- JavaScript学习 Ⅲ
六. 面向对象 对象属于一种复合的数据类型,在对象中可以保存多个不同的数据类型的属性. 对象分类 内建对象 由ES标准种定义的对象.比如:Math String Number 宿主对象 由JS的运行环 ...
- vue组件通讯之provide / inject
什么是 provide / inject [传送门] vue的组件通讯方式我们熟知的有 props $emit bus vuex ,另外就是 provide/inject provide/inject ...
- flask 源码专题(六):session处理机制
前言 flask_session是flask框架实现session功能的一个插件,用来替代flask自带的session实现机制,flask默认的session信息保存在cookie中,不够安全和灵活 ...
- Flask 基础组件(三):路由系统
1. 常见路由 @app.route('/user/<username>') @app.route('/post/<int:post_id>') @app.route('/po ...
- IOS中input键盘事件keyup 的兼容解决办法
用input监听键盘keyup事件,在安卓手机浏览器中是可以的,但是在ios手机浏览器中很慢,用输入法输入之后,并未立刻相应keyup事件. 解决办法: 在ios设备上可以用html5的input事件 ...
- 用前端姿势玩docker【二】dockerfile定制镜像初体验
前言 书接上文,关于dockerfile指令的api在此处不做赘述,在此只是记录下注意事项: '示坑以埋之'. 配置指令 FROM dockerfile必须以此开头 一个dockerfile可执行添加 ...
- InceptionV4
目录 1. inception v4 2. Inception-resnet-v1 & Inception-resnet-v2 2.1 Inception-resnet-v1的组成模块 2.2 ...
- ajax原生js封装
不带注释的 function ajax(json) { json.type = json.type ? json.type : 'get'; json.async = json.async == fa ...