zoukankan      html  css  js  c++  java
  • 团购码,你知多少?——线性同余产生随机数

    在互联网时代,经常会有产生【随机数】的应用场景。

    比如说最常见的团购业务,用户购买一张团购券,然后客户的手机中会接收到一个随机的团购码。客户拿着这个团购码去门店验证消费。

    相面大家都对上面的这种方式比较熟悉。如果站上技术的角度,我们来分析一下这个【团购码】其实还是有很多细节在里面的。接下来我们来对这部分细节进行探讨。

    假设用点击领用团购码,产生一个10000 以内的随机数。该数字发到用户手机上,作为验证凭证。

    那么这个团购码需要满足下面的几个条件:

    1:每次都是随机产生,用户不能轻易猜测到下一个验证码。

    2:团购码的数值范围必需【00001,10000】。——实际中这个数字会比较大。

    3:用户领用的团购码是决对唯一的,即产生的每个数字,只会出现一次。不会存在多个用户领用同一个验证码的情况。

    上面条件的技术难点在于如何生成不重复的随机数

    大家知道,一般我们用的编程语言所提供的随机数方法,都不能保证下一次的随机数和前面的不重复。即我们生成了100个随机数里面,就可能会有N个是重复。

    那么如何保证其不重复性? 很容易想到的方案是,每次生成一个新的随机数后,再去和前面的所有的随机数进行比较,如果重复则抛弃。

    但是这样做好么?假设要生成1000个随机数,每次都和前面的进行比较好像问题不大。要是要1亿的范围呢?

    我有个朋友正好在一家知明的团购公司工作,我向他了解下他们公司生成团购码的方法。

    总体思路是:

    1:生成一批待用的码放在码池中。用的是编程语言所提供的随机数方法。

    2:用户领用码后,生成一条领用记录,并且码池中除非该码。

    3:定期检查码池,生成新的码放入池中。

    同样面临重复码的问题。如果两个用户a,b 在不同时间段领到了相同的团购码。用户a 比用户 b 更先一步去门店消费,然后更新该团购码的状态。那么用户b的那个码也会更新,则用户b来消费的时候会发现该码已经被用了。

    他们如何解决这个问题,在步骤1 批量生成码的时想,先check码池的所有记录是否重复。当然最好再和用户领用记录check一下。

    这样会带来性能上的很大消耗。或许可以想一些办法可以减少这方面的损失,比如码池放更多的码,过期的领用的记录及时清理。

    更多的具体细节,不再去深入。

    上面的做法,多多少少不是很理想。没有在关键点上解决问题——用一种算法每次生成一个和前面不重复的随机数。

    基于上述类似场景,提供一个《线性同余产生随机数》算法,每次生成一个不重复的随机数。

    算法参考:http://www.asmedu.net/algorithm.jsp?index=46

    线性同余产生随机数算法解析:

    Xn+1 = ( a * Xn + c ) mod  m ,n >= 0

    其中:  0 < m ;0 <= a<m ;  0 <=c<m 

    开始指定一个X0( 0<=X0<m ),依赖上次的值Xn,每次得到一个数Xn+1。根据这个算法所求的随机数序列{X0,X1,...Xn},称作线性同余序列。 

    同余序列总是进入一个循环,它最终必定在n个数之间无休止的重复循环。它的最大循环周期为m。 

    得到最大的周期m的条件如下: 
    (1)c与m为互质数。
    (2)对于整除m的每个素数p,b=a-1是p的倍数。
    (3)如果m是4的倍数,则b也是4的倍数。 

    以取10000个 随机数为例,m = 10000;按最大的周期条件设定c = 3; a = 21; x0=4。

    代码如下:

    1         public static void RandomGenerator(ref long previousVaule)
    2         {
    3             //Xn+1 = ( aXn + c ) mod  m ,n >= 0 
    4             long m = 10000L;
    5             long c = 3L;
    6             long a = 21L;
    7 
    8             previousVaule = (a * previousVaule + c) % m;
    9         }
                long ab = 4;
                HashSet<long> hash = new HashSet<long>();
    
                for (int i = 0; i < 10000; i++)
                {
                    RandomGenerator(ref ab);
                    hash.Add(ab);
                    Console.WriteLine(ab);
                }
                Console.WriteLine("总数:"+hash.Count);

    运行结果:

    经测试可以验证,10000次随机将穷举所有< 10000的数字不会发生重复。现实应用中,还要解决分布式情况下,对上次的值Xn依赖的争用问题。

    最后,大家可能还是有疑问。这样的随机码冒似可以破解。这批随机码是有规率的对吗?

    所以最后对每次批量生成的码,要再把它们的顺序打乱一下再存到池中。

    最重要的是下批量生成的码将不会和前面的重复。

  • 相关阅读:
    包图网+千图网图片代下
    Java基于二维数组自定义的map
    java23种设计模式-行为型模式-中介者模式
    基于SpringBoot、Redis和RabbitMq的商品秒杀处理
    wps+稻壳vip账号免费分享
    wps+稻壳vip15天领取地址
    图精灵、易图、笔图,vip免费分享
    文库、氢元素、办图、六图,vip免费分享
    快图网、千库,go设计,vip免费分享
    MySQL索引规范及优化
  • 原文地址:https://www.cnblogs.com/zrhai/p/4071023.html
Copyright © 2011-2022 走看看