令牌桶算法和漏桶算法python_如何实现漏桶算法与令牌桶算法
作者:大数据孟小鹏(Java架构沉思录做了部分修改)
原文:https://blog.csdn.net/mengxpFighting/article/details/79117934
Java中对于生产者消费者模型,或者小米手机营销(1分钟卖多少台手机)等都存在限流的思想在里面。
关于限流目前存在两大类:从线程并发数角度(jdk1.5 Semaphore)限流和从速率限流(guava)。
Semaphore:从线程并发数限流。
RateLimiter:从速率限流。目前常见的算法是漏桶算法和令牌算法。
令牌桶算法。相比漏桶算法而言区别在于,令牌桶是会去匀速的生成令牌,拿到令牌才能够进行处理,类似于匀速往桶里放令牌。
漏桶算法是:生产者消费者模型,生产者往木桶里生产数据,消费者按照预先定义的速度去消费数据。
应用场景:
漏桶算法:必须读写分离的情况下,限制读取的速度。
令牌桶算法:必须读写分离的情况下,限制写的速率。
实现的方法都是一样的,通过RateLimiter来实现。
对于多线程场景下,很多时候使用的类都是原子性的,但是由于代码逻辑的原因,也可能发生线程安全问题。
1. 关于RateLimter和Semphore简单用法
package concurrent;
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.*;
import java.util.stream.IntStream;
import static java.lang.Thread.currentThread;
/**
* ${DESCRIPTION}
* 关于限流 目前存在两大类,从线程个数(jdk1.5 Semaphore)和RateLimiter速率(guava)
* Semaphore:从线程个数限流
* RateLimiter:从速率限流 目前常见的算法是漏桶算法和令牌算法,下面会具体介绍
*
* @author mengxp
* @version 1.0
* @create 2018-01-15 22:44
**/
public class RateLimiterExample {
//Guava 0.5的意思是 1秒中0.5次的操作,2秒1次的操作 从速度来限流,从每秒中能够执行的次数来
private final static RateLimiter limiter=RateLimiter.create(0.5d);
//同时只能有三个线程工作 Java1.5 从同时处理的线程个数来限流
private final static Semaphore sem=new Semaphore(3);
private static void testSemaphore(){
try {
sem.acquire();
System.out.println(currentThread().getName() ' is doing work...');
TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
sem.release();
System.out.println(currentThread().getName() ' release the semephore..other thread can get and do job');
}
}
public static void runTestSemaphore(){
ExecutorService service = Executors.newFixedThreadPool(10);
IntStream.range(0,10).forEach((i)->{
//RateLimiterExample::testLimiter 这种写法是创建一个线程
service.submit(RateLimiterExample::testSemaphore);
});
}
/**
* Guava的RateLimiter
*/
private static void testLimiter(){
System.out.println(currentThread().getName() ' waiting ' limiter.acquire());
}
//Guava的RateLimiter
public static void runTestLimiter(){
ExecutorService service = Executors.newFixedThreadPool(10);
IntStream.range(0,10).forEach((i)->{
//RateLimiterExample::testLimiter 这种写法是创建一个线程
service.submit(RateLimiterExample::testLimiter);
});
}
public static void main(String[] args) {
IntStream.range(0,10).forEach((a)-> System.out.println(a));//从0-9
//runTestLimiter();
runTestSemaphore();
}
}
2. 实现漏桶算法
package concurrent.BucketAl;
import com.google.common.util.concurrent.Monitor;
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import static java.lang.Thread.currentThread;
/**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-20 22:42
* 实现漏桶算法 实现多线程生产者消费者模型 限流
**/
public class Bucket {
//定义桶的大小
private final ConcurrentLinkedQueue container=new ConcurrentLinkedQueue<>();
private final static int BUCKET_LIMIT=1000;
//消费者 不论多少个线程,每秒最大的处理能力是1秒中执行10次
private final RateLimiter consumerRate=RateLimiter.create(10d);
//往桶里面放数据时,确认没有超过桶的最大的容量
private Monitor offerMonitor=new Monitor();
//从桶里消费数据时,桶里必须存在数据
private Monitor consumerMonitor=new Monitor();
/**
* 往桶里面写数据
* @param data
*/
public void submit(Integer data){
if (offerMonitor.enterIf(offerMonitor.newGuard(()->container.size()
try {
container.offer(data);
System.out.println(currentThread() ' submit..' data ' container size is :[' container.size() ']');
} finally {
offerMonitor.leave();
}
}else {
//这里时候采用降级策略了。消费速度跟不上产生速度时,而且桶满了,抛出异常
//或者存入MQ DB等后续处理
throw new IllegalStateException(currentThread().getName() 'The bucket is ful..Pls latter can try...');
}
}
/**
* 从桶里面消费数据
* @param consumer
*/
public void takeThenConsumer(Consumer consumer){
if (consumerMonitor.enterIf(consumerMonitor.newGuard(()->!container.isEmpty()))){
try {
//不打印时 写 consumerRate.acquire();
System.out.println(currentThread() ' waiting' consumerRate.acquire());
Integer data = container.poll();
//container.peek() 只是去取出来不会删掉
consumer.accept(data);
}finally {
consumerMonitor.leave();
}
}else {
//当木桶的消费完后,可以消费那些降级存入MQ或者DB里面的数据
System.out.println('will consumer Data from MQ...');
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.1 漏桶算法测试类
package concurrent.BucketAl;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import static java.lang.Thread.currentThread;
/**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-20 23:11
* 漏桶算法测试
* 实现漏桶算法 实现多线程生产者消费者模型 限流
**/
public class BuckerTest {
public static void main(String[] args) {
final Bucket bucket = new Bucket();
final AtomicInteger DATA_CREATOR = new AtomicInteger(0);
//生产线程 10个线程 每秒提交 50个数据 1/0.2s*10=50个
IntStream.range(0, 10).forEach(i -> {
new Thread(() -> {
for (; ; ) {
int data = DATA_CREATOR.incrementAndGet();
try {
bucket.submit(data);
TimeUnit.MILLISECONDS.sleep(200);
} catch (Exception e) {
//对submit时,如果桶满了可能会抛出异常
if (e instanceof IllegalStateException) {
System.out.println(e.getMessage());
//当满了后,生产线程就休眠1分钟
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
}).start();
});
//消费线程 采用RateLimiter每秒处理10个 综合的比率是5:1
IntStream.range(0, 10).forEach(i -> {
new Thread(
() -> {
for (; ; ) {
bucket.takeThenConsumer(x -> {
System.out.println(currentThread() 'C..' x);
});
}
}
).start();
});
}
}
3. 令牌桶算法
package concurrent.TokenBucket;
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.Thread.currentThread;
import static java.lang.Thread.interrupted;
/**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-21 0:18
* 令牌桶算法。相比漏桶算法而言区别在于,令牌桶是会去匀速的生成令牌,拿到令牌才能够进行处理,类似于匀速往桶里放令牌
* 漏桶算法是:生产者消费者模型,生产者往木桶里生产数据,消费者按照定义的速度去消费数据
*
* 应用场景:
* 漏桶算法:必须读写分流的情况下,限制读取的速度
* 令牌桶算法:必须读写分离的情况下,限制写的速率或者小米手机饥饿营销的场景 只卖1分种抢购1000
*
* 实现的方法都是一样。RateLimiter来实现
* 对于多线程问题查找时,很多时候可能使用的类都是原子性的,但是由于代码逻辑的问题,也可能发生线程安全问题
**/
public class TokenBuck {
//可以使用 AtomicInteger 容量 可以不用Queue实现
private AtomicInteger phoneNumbers=new AtomicInteger(0);
private RateLimiter rateLimiter=RateLimiter.create(20d);//一秒只能执行五次
//默认销售500台
private final static int DEFALUT_LIMIT=500;
private final int saleLimit;
public TokenBuck(int saleLimit) {
this.saleLimit = saleLimit;
}
public TokenBuck() {
this(DEFALUT_LIMIT);
}
public int buy(){
//这个check 必须放在success里面做判断,不然会产生线程安全问题(业务引起)
//原因当phoneNumbers=99 时 同时存在三个线程进来。虽然phoneNumbers原子性,但是也会发生。如果必须写在这里,在success
//里面也需要加上double check
/* if (phoneNumbers.get()>=saleLimit){
throw new IllegalStateException('Phone has been sale ' saleLimit ' can not buy more...')
}*/
//目前设置超时时间,10秒内没有抢到就抛出异常
//这里的TimeOut*Ratelimiter=总数 这里的超时就是让别人抢几秒,所以设置总数也可以由这里的超时和RateLimiter来计算
boolean success = rateLimiter.tryAcquire(10, TimeUnit.SECONDS);
if (success){
if (phoneNumbers.get()>=saleLimit){
throw new IllegalStateException('Phone has been sale ' saleLimit ' can not buy more...');
}
int phoneNo = phoneNumbers.getAndIncrement();
System.out.println(currentThread() ' user has get :[' phoneNo ']');
return phoneNo;
}else {
//超时后 同一时间,很大的流量来强时,超时快速失败。
throw new RuntimeException(currentThread() 'has timeOut can try again...');
}
}
}
3.1 令牌桶算法的测试类
package concurrent.TokenBucket;
import java.util.stream.IntStream;
/**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-21 0:40
**/
public class TokenBuckTest {
public static void main(String[] args) {
final TokenBuck tokenBuck=new TokenBuck(200);
IntStream.range(0,300).forEach(i->{
//目前测试时,让一个线程抢一次,不用循环抢
//tokenBuck::buy 这种方式 产生一个Runnable
new Thread(tokenBuck::buy).start();
});
}
}
令牌桶算法和漏桶算法python_如何实现漏桶算法与令牌桶算法相关推荐
- 排序算法--(冒泡排序,插入排序,选择排序,归并排序,快速排序,桶排序,计数排序,基数排序)
一.时间复杂度分析 - **时间复杂度**:对排序数据的总的操作次数.反应当n变化时,操作次数呈现什么规律 - **空间复杂度**:算法在计算机内执行时所需要的存储空间的容量,它也是数据规模n的函数. ...
- 十大排序算法详解(二)归并排序、堆排序、计数排序、桶排序、基数排序
文章目录 一.归并排序 1.1 归并排序基础[必会知识] 1.1.1 递归实现 1.1.2 非递归实现 1.2 归并排序优化 1.2.1 小数组使用插入排序 1.2.2 避免多余比较 1.2.3 节省 ...
- 两个矩阵是否相交的算法_收藏 | 计算机、数学、运筹学等领域的32个重要算法...
来源:大数据 本文约2500字,建议阅读5分钟. 本文为你分享计算机.数学.运筹学等领域的32个重要算法. [ 导读 ] 奥地利符号计算研究所(Research Institute for Symbo ...
- 重拾算法(3)——用458329个测试用例全面测试二叉树和线索二叉树的遍历算法
重拾算法(3)--用458329个测试用例全面测试二叉树和线索二叉树的遍历算法 在"上一篇"和"上上一篇"中,我给出了二叉树和线索二叉树的遍历算法.给出算法容易 ...
- DL框架之MXNet :神经网络算法简介之MXNet 常见使用方法总结(神经网络DNN、CNN、RNN算法)之详细攻略(个人使用)
DL框架之MXNet :神经网络算法简介之MXNet 常见使用方法总结(神经网络DNN.CNN.RNN算法)之详细攻略(个人使用) 相关文章 DL框架之MXNet :深度学习框架之MXNet 的简介. ...
- DL之NN/CNN:NN算法进阶优化(本地数据集50000张训练集图片),六种不同优化算法实现手写数字图片识别逐步提高99.6%准确率
DL之NN/CNN:NN算法进阶优化(本地数据集50000张训练集图片),六种不同优化算法实现手写数字图片识别逐步提高99.6%准确率 目录 设计思路 设计代码 设计思路 设计代码 import mn ...
- 改进的有效边表算法_优硕微展 | 张和慧:基于邻域保持嵌入算法的间歇过程故障检测研究...
基于邻域保持嵌入算法的 间歇过程故障检测研究 The Research on batch process fault detection based on Neighborhood Preservin ...
- WEKA算法开发——记一次不太成功的遗传属性加权贝叶斯算法实验
WEKA算法开发--记一次不太成功的遗传属性加权贝叶斯算法实验 1. WEKA介绍 2. 使用WEKA开发自己的算法 3. ~~总结~~ 吐槽 1. WEKA介绍 Weka平台是一种数据分析+模式识别 ...
- 【安全算法之概述】一文带你简要了解常见常用的安全算法(RT-Thread技术论坛优秀文章)
[安全算法之概述]一文带你简要了解常见常用的安全算法 0 前言 1 算法的大致分类 2 对称加解密算法 2.1 DES/TDES算法 2.2 AES算法 2.3 SM4算法 2.4 RC2.RC4算法 ...
- 基于音乐/电影/图书的协同过滤推荐算法代码实现(基于用户推荐、基于项目推荐、基于SlopeOne算法推荐、基于SVD算法推荐、混合加权推荐)
基于音乐/电影/图书的协同过滤推荐算法代码实现(基于用户推荐.基于项目推荐.基于SlopeOne算法推荐.基于SVD算法推荐.加权混合推荐) 一.开发工具及使用技术 MyEclipse10.jdk1. ...
最新文章
- [JavaScript] Math里的api
- 网红 AI 高仿坎爷发布说唱情歌,歌迷:堪比真人原声
- Aspose.Cells设置单元格格式
- python哨兵循环_Python通用循环的构造方法实例分析
- tcp 的ack, seq
- SVN 创建仓库操作
- ITK:将蒙版的反面应用于图像
- 为了适应云数据库mySQL产品_为了适应不同的应用场景,云数据库mysql版提供的产品系列包括哪些...
- SkyDrive Explorer 把微软25GB网络硬盘搬进“我的电脑”
- 催人泪下!做技术打铁还需自身硬
- sunplus8202v BIN文件中LOGO的替换工具设计思路
- Gartner 解析容器新发展, 阿里云、AWS布局最完善
- adb启动app_ADB 命令大全
- 【软件工程】对软件工程课程的希望及个人目标
- 如何做到秒级扩容1000加业务节点
- Oracle用户、身份、数据类型、和mysql的区别
- jBox,实现批量查询
- C语言——矩阵计算(转置、加法、减法、数乘、乘法)
- 使用思科模拟器 Cisco Packet Tracer 模拟交换机基本配置
- 如何搭建并成功运营手游联运平台?