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 ...
随机推荐
- 解决for循环里获取到的索引是最后一个的问题
方法一 原理: 利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入 利用 bind 函数部分执行的特性 代码 1: for (var i = 0; i < 10; i+ ...
- QQ音乐Android客户端Web页面通用性能优化实践
QQ音乐 Android 客户端的 Web 页面日均 PV 达到千万量级,然而页面的打开耗时与 Native 页面相距甚远,需要系统性优化.本文将介绍 QQ 音乐 Android 客户端在进行 Web ...
- Java 线程与同步的性能优化
本文探讨的主题是,如何挖掘出Java线程和同步设施的最大性能. 1.线程池与ThreadPoolExecutor 1)线程池与ThreadPoolExecutor 线程池的实现可能有所不同,但基本概念 ...
- swagger -- 前后端分离的API接口
文章目录 一.背景 二.swagger介绍 三.在maven+springboot项目中使用swagger 四.swagger在项目中的好处 五.美化界面 参考链接:5分钟学会swagger配置 参考 ...
- 【Kafka】Kafka测试时控制台日志级别修改
在学习Kafka客户端时日志打的飞起,根本看不到自己发的消息,找了半天网上竟然没有这方面的资料.想了下依赖关系,这里应该只要把slf4j的日志级别调整应该就ok了. static { LoggerCo ...
- 【Java面试】- 并发容器篇
JDK 提供的并发容器 ConcurrentHashMap: 线程安全的 HashMap CopyOnWriteArrayList: 线程安全的 List,在读多写少的场合性能非常好,远远好于 Vec ...
- 关于C#反射(转载)
反射的用途: (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例. (2)使用Module了解包含模块的程序集以及模块中 ...
- vue学习(三) v-bind指令
//html <div id="app"> <input type="button" value="ok" v-bind: ...
- 互联网找的e是无理数的初等证明
e的两种计算方式 \(e=lim_{n \to \infty}(1+\frac{1}{n})^n\) \(e=\sum_{n=0}^{+\infty}\frac{1}{n!}\) \(即,e=\fra ...
- 《吊打面试官》系列-Redis基础知识
前言Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联网公司面一次拿一次offer的面霸(请允许我使用一下 ...