Randomly divide one million red envelopes

Year approaches, various promotional activities on-line soon, there is a demand for a similar kind of treasure to pay the set of Five, after the user cobble together a card, you can divide one million red envelopes.

Because the number of such events collect divide is certainly a lot of random again after direct deduction, the feeling is not very suitable.

Reference: https: //www.cnblogs.com/canglong/p/canglong001.html utm_source = itdadao & utm_medium = referral?

The general idea is as follows: according to collect the card number of the user, such as 5, and so the length of the array generates a random number [2,5,9,8,6]. The random number value inside the array elements and the proportions of the entire array (30) to calculate the size of each red occupied, if it is 10 divide quick money. Generate real red array [(2/30) * 10 (5/30) * 10, ...], do not last a pro rata basis, that is direct the remaining money, so there is this last amount may appear maximum, then we can generate this array of re-shuffling about, so in order to ensure better randomness. Finally, these have generated a good red envelope into the list redis in. Wait until carve red envelopes, each user came directly from the pop-up list in an element on the list, because the list has always been randomly generated. This also just to meet the randomness.

Generating an array of red (which some details are comments in the code):

Package com.nijunyang.algorithm.redpackage; 

Import java.math.BigDecimal;
 Import of java.util.ArrayList;
 Import java.util.Collections;
 Import java.util.List;
 Import java.util.Random; 

/ ** 
 * the Description: 
 the Created by nijunyang ON 2019/12/12 * 22:03 
 * / 
public  class RedPackageUtils { 

    / ** 
     * according to the number randomly assigned red 
     * @param moneyTotal total red 
     * @param number number The 
     * @return a random collection of red envelopes
      * / 
    public  staticList <the BigDecimal> shareMoney (moneyTotal the BigDecimal, int Number) {
         IF (moneyTotal.compareTo ( new new the BigDecimal (Number) .multiply ( new new the BigDecimal ( "0.01"))) <0 ) {
             the throw   new new a RuntimeException ( "person to curbing money. " ); 
        } 
        // calculated points, money conversion component 
        Long money = moneyTotal.multiply (BigDecimal.valueOf (100 )) longValue in ();.
         // generate a number and the same array, the distribution of random numbers, and compute a random the number of accounting, in accordance with the corresponding proportion cents. 
        Double randomCount = 0 ;
         Double [] = randomArr new new  Double [Number]; 
        the Random Random= New new the Random ();
         for ( int I = 0; I <Number; I ++ ) {
             int R & lt random.nextInt = (Number * 100) +. 1;   // avoid 0 
            randomArr [I] = R & lt; 
            randomCount + = R & lt ; 
        } 
        // The proportion of each random number calculated amount per red 
        Long alreadyShare = 0 ; 
        List <the BigDecimal> = moneyList new new the ArrayList <> (number);
         for ( int I = 0; I <number; I ++ ) {
             / / per share 
            double= randomArr ratio [I] / randomCount;
             / ** 
             * rounded down, then round if used, may result in a plurality of rounded up, not the last sub-finished, but without enough money, and rounding down can be positive and End points 
             * this may result in the last, the last remaining share of relatively little, and then finally the entire collection reshuffle shuffle 
             * / 
            Long shareMoney = ( Long ) Math.floor (* ratio Money);
             // probability is too small , the total number is too small, rounded down may occur 0, 1 cent minimum processing 
            IF (shareMoney == 0 ) { 
                shareMoney = 1 ; 
            } 
            alreadyShare + = shareMoney;
             IF (I <Number - 1 ) { 
                moneyList.add ( new new BigDecimal (shareMoney) .divide (new new the BigDecimal (100 ))); 
            } the else {
                 // the last of the remaining money directly to the sub past 
                moneyList.add ( new new the BigDecimal (Money - alreadyShare + shareMoney) .divide ( new new the BigDecimal (100 ))); 
            } 
        } 
        / / shuffle 
        Collections.shuffle (moneyList);
         return moneyList; 
    } 
}

We found that there are two more pits in time to put into place inside redis

1.ListOperations of leftPushAll (K var1, Collection <V> var2) The method is based on a whole set of elements to put, then use this method to say push, then redis element of a list inside. I do not know this has always been a bug, or I understand and write this approach people on this method is not the same. (Spring-data-redis 2.1.10)

2..ListOperations of leftPushAll (K var1, V ... var2 ) this method  the number leader spent large can not be added, will be reported IO exception, because they do not know how many collect, so I did the tens of thousands, hundreds of thousands question, one million will be reported IO exception of: (java.io.IOException: forcibly closed by the remote host an existing connection). The next test can be added to the length of one million, 1.1 million will be given the length, there is no depth study, there should be the code length limit, if the length is too long, it is recommended into several arrays in turn added to it.

redis Code: tests are easy to get request with

 

    @GetMapping ( "/ Push / redpackage / Money {} / {Number}" )
     public ResponseEntity <Long> pushRedPackage (@PathVariable Money Integer, Integer Number @PathVariable) { 

        List <the BigDecimal> redPackageList = RedPackageUtils.shareMoney (BigDecimal.valueOf ( Money), number);
         / ** 
         * leftPushAll (K var1, collection <V> var2) to the entire set is not stored in the form of a single element storage element 
         * leftPushAll (K var1, V ... var2) through the large number of head can not be added, will be reported IO exception, the next test length 1,000,000 1,100,000 length will be given a 
         * / 
        String [] redPackages = new new String [redPackageList.size ()];
         for ( int I = 0; I <redPackages. length; I ++  ) {
            redPackages [I]= redPackageList.get(i).toString();
        }
        Long length = listOperations.leftPushAll(SHARE_RED_PACKAGE_KEY, redPackages);
        return new ResponseEntity<>(length, HttpStatus.OK);
    }

    @GetMapping("/share/redpackage")
    public ResponseEntity<Object> share() {
        Object money = listOperations.leftPop(SHARE_RED_PACKAGE_KEY);
        if (money == null) {
            return new ResponseEntity<>("红包已瓜分完毕", HttpStatus.OK);
        }
        return new ResponseEntity<>(money, HttpStatus.OK);
    }

 

With Jmeter tried, carve red interface (data from the pop-up list redis's) can reach more than 10,000 point of QPS, from the local stand-alone service, redis also installed in vmware virtual machine, or will the 10,000+ feel.

Guess you like

Origin www.cnblogs.com/nijunyang/p/12037705.html