缓存随机结果,提高响应时间

     最近在业务中,遇到一个有趣的业务场景, 有4个(为了说明问题只说4个)  随机物品, 分别是 A, B ,C ,D;

其中 B C D 的权重是1000,A的权重是1; 也就是说运营希望A 出现的概率很低,A很稀有尽量提高用户抽到第四次才能出A,A必出(保底),但是A 出现的根据随机次数的增加而增加,随机到A后刷新概率从头随机。

实际场景中随机奖品 有十几个,这里要说明的是,当用户非常多,访问量非常大的时候,我们可以对随机结果进行缓存器 ,这样下次随机的时候,就可以快速拿到随机结果。这里强调一点:预缓存随机结果,简化传递参数。 

    第一次随机出A的概率  1/3001;

    第二次随机出A的概率  1/2001;

    第三次随机出A的概率  1/1001;

    第四次随机出A的概率   1/1;//必出

先写一段测试代码

import java.util.HashMap;

import java.util.Map.Entry;

public class Test {

static HashMap<Integer,Integer> map=new HashMap<>();//记录 随机出现A 在次数中的统计

//生成测试数据A B C D 四个概率的情况进行测试

static String[] values=new String[] {"D","C","B","A"};//把A放到最後,方便保底

static int[] weights=new int[] {1000,1000,1000,1};

public static void main(String[] args) {

int roundCount = 3001000;

for(int i=0;i<roundCount;i++) {//循环10000次,每次都抽到A 才返回

randomA ();

}

System.out.println("随机"+roundCount+"轮 ");

for(Entry<Integer, Integer> entrentryy:map.entrySet()) {

Entry<Integer, Integer> entry = entrentryy;

int count=entry.getKey()+1;

System.out.println("第"+count+"次出现A的数量是:"+entry.getValue());

}

}

private static void randomA( ) {

for(int j=0;j<4;j++) {

RandomModel<String> random=new RandomModel<>();//隨機模型

//存入隨機項

for(int h=j;h<4;h++) {

random.put(weights[h], values[h]);

}

//隨機

String value=random.random();

if("A".equals(value)) {

Integer num= map.get(j);

if(num==null) {

num=0;

}

num++;

map.put(j, num);//統計在第幾次出現 A

break;

}

}

}

}

------------------------------------------------------------------------------------------------------

import java.util.ArrayList;

import java.util.Random;

public class RandomModel<T> {

ArrayList<Item<T>> items=new ArrayList < Item<T>>();//存储所有参与权重的随机数

private int sumWeight;//权重总合

/** 存入一个概率 物品(t)

* @param weight 权重

* @param t

*/

public void put(int weight,T t) {

if(weight<1) throw new RuntimeException("权重值应该大于0的整数");

sumWeight+=weight;

Item<T> item=new Item<>();

item.odds=sumWeight;

item.t=t;

items.add(item);

}

public T random() {

int randomValue=new Random().nextInt(sumWeight);//根据权重总和计算随机数。例如,如果权重总和是100,随机数0~99

for(Item<T> item:this.items) {

if(randomValue<item.odds) {

return item.t;

}

}

throw new RuntimeException("永远都不执行的代码");

}

class Item<T>{

public int odds;

public T t;

}

}

---------------------------------------------------------------------------------------------------------------------

 代码基础添加了打印 消耗的时间。

控制台输出:

随机3001000轮 總耗時: 1571毫秒

第1次出现A的数量是:1019

第2次出现A的数量是:1439

第3次出现A的数量是:2986

第4次出现A的数量是:2995556

-----------------------------------------------------------------------------

当用户负载较高,用户请求次数较高时,预缓存随机结果,可以大大提高高峰时的响应时间。

例子中没一轮必出A,当随机出A的时候,就结束这轮随机。

可以利用服务器空间存储结果,以换取对客户端的快速响应改造后的test2 

import java.util.ArrayList;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.List;

import java.util.Map.Entry;

public class Test2 {

static HashMap<Integer,Integer> map=new HashMap<>();//记录 随机出现A 在次数中的统计

//生成测试数据A B C D 四个概率的情况进行测试

static String[] values=new String[] {"D","C","B","A"};//把A放到最後,方便保底

static int[] weights=new int[] {1000,1000,1000,1};

public static void main(String[] args) {

int roundCount = 3001000;

for(int i=0;i<roundCount;i++) {//循环10000次,每次都抽到A 才返回

randomValue();

}

long time=System.currentTimeMillis();

for(int i=0;i<roundCount;i++) {//循环10000次,每次都抽到A 才返回

randomFromCache();

}

time=System.currentTimeMillis()-time;

System.out.println("随机"+roundCount+"轮 读取缓存總耗時: "+time+ "毫秒 ");

for(Entry<Integer, Integer> entrentryy:map.entrySet()) {

Entry<Integer, Integer> entry = entrentryy;

int count=entry.getKey()+1;

System.out.println("第"+count+"次出现A的数量是:"+entry.getValue());

}

}

static LinkedList<List<String>> resultCache=new LinkedList<>();//緩存結果

private static void randomValue( ) {

ArrayList<String> arr=new ArrayList<>();

resultCache.addLast(arr);//緩存

for(int j=0;j<4;j++) {

RandomModel<String> random=new RandomModel<>();//隨機模型

//存入隨機項

for(int h=j;h<4;h++) {

random.put(weights[h], values[h]);

}

//隨機

String value=random.random();

arr.add(value);

if("A".equals(value)) {

   break;

}

}

}

private static void randomFromCache() {

List<String> arr=resultCache.removeFirst();

for(int j=0;j<arr.size();j++) {

String value=arr.get(j);

if("A".equals(value)) {

Integer num= map.get(j);

if(num==null) {

num=0;

}

num++;

map.put(j, num);//統計在第幾次出現 A

break;

}

}

}

}

--------------------------------------------------执行测试--------------------------------------------------------

控制台输出

随机3001000轮 读取缓存總耗時: 164毫秒

第1次出现A的数量是:1005

第2次出现A的数量是:1523

第3次出现A的数量是:2977

第4次出现A的数量是:2995495

看到响应时间缩短了好几倍,这个就提高了响应客户端的速度。测试代码中包含,统计代码也比较耗时,为了更好的查看使用缓存带来的速度提升,我们去掉统计个数的代码,

Integer num= map.get(j);

if(num==null) {

num=0;

}

num++;

map.put(j, num);//統計在第幾次出現 A

再看结果。

------------------------------------------------------------------------------------------------------------------------

不执行缓存:随机3001000轮 總耗時: 1561毫秒

随机3001000轮 读取缓存總耗時: 109毫秒

这里出了读取缓存需要的时间以外,还要额外在存入缓存时消耗的时间,加上随机数据再存入缓存,需要的时间总体更多,但是对于 有服务器的应用来说,有效的使用缓存,提高了服务器响应时间15倍左右,这对于用于请求多的时候,会大大提高性能。 这里还有线程安全都能问题,由于不是要叙述的重点,所以忽略。

       通过使用randomModel 类可以很简单的随机 使用权重的业务,使用jvm(java虚拟机)内存以空间换取时间能大大提高对客户端的响应时间,从而提高负载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值