github.com/zhongdalu/gf@v1.0.0/g/util/grand/grand_intn.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  
     7  package grand
     8  
     9  import (
    10  	"crypto/rand"
    11  	"encoding/binary"
    12  	"os"
    13  )
    14  
    15  const (
    16  	// Buffer size for uint32 random number.
    17  	gBUFFER_SIZE = 10000
    18  )
    19  
    20  var (
    21  	// Buffer chan.
    22  	bufferChan = make(chan uint32, gBUFFER_SIZE)
    23  )
    24  
    25  // It uses a asychronous goroutine to produce the random number,
    26  // and a buffer chan to store the random number. So it has high performance
    27  // to generate random number.
    28  func init() {
    29  	step := 0
    30  	buffer := make([]byte, 1024)
    31  	go func() {
    32  		for {
    33  			if n, err := rand.Read(buffer); err != nil {
    34  				panic(err)
    35  				os.Exit(1)
    36  			} else {
    37  				// 使用缓冲区数据进行一次完整的随机数生成
    38  				for i := 0; i < n-4; {
    39  					bufferChan <- binary.LittleEndian.Uint32(buffer[i : i+4])
    40  					i++
    41  				}
    42  				// 充分利用缓冲区数据,随机索引递增
    43  				for i := 0; i < n; i++ {
    44  					step = int(buffer[0]) % 10
    45  					if step != 0 {
    46  						break
    47  					}
    48  				}
    49  				if step == 0 {
    50  					step = 2
    51  				}
    52  				for i := 0; i < n-4; {
    53  					bufferChan <- binary.BigEndian.Uint32(buffer[i : i+4])
    54  					i += step
    55  				}
    56  			}
    57  		}
    58  	}()
    59  }
    60  
    61  // Intn returns a int number which is between 0 and max - [0, max).
    62  //
    63  // Note:
    64  // 1. The result is greater than or equal to 0, but less than <max>;
    65  // 2. The result number is 32bit and less than math.MaxUint32.
    66  func Intn(max int) int {
    67  	n := int(<-bufferChan) % max
    68  	if (max > 0 && n < 0) || (max < 0 && n > 0) {
    69  		return -n
    70  	}
    71  	return n
    72  }