github.com/MeteorsLiu/rand@v0.0.0-20230523094032-b55484ce1d5d/readme.md (about)

     1  # An optimized math/rand
     2  
     3  Concurrency safe math/rand, optimized for high concurrent pseudo number generating.
     4  
     5  # Why?
     6  Go's random algorithm is great, its pseudo randomness behaves well.
     7  
     8  However, the standard library uses a global mutex lock to ensure its safety of concurrency.
     9  
    10  That's not a good things.
    11  
    12  In a high concorrent pseudo number generating case, like a online game, the global mutex will increase the latency of requests when the parallel requests is incrasing.
    13  
    14  ## How to solve?
    15  
    16  It's easy to avoid the lock.
    17  
    18  1. Pool
    19  2. Atomic operation
    20  
    21  In this porject, I choose to use the pool. The other one([Wyhash](https://github.com/MeteorsLiu/wyhash)) uses Atomic Operation.
    22  
    23  However, if only one goroutine is using, there's no necessity to use the pool, because pulling out the pool and pushing into the pool cost, it's not free.
    24  
    25  
    26  So I use a CAS lock to check whether only one goroutine uses it.
    27  
    28  If yes, use a global lockless one.No, grab it from the pool.
    29  
    30  
    31  # What's new?
    32  
    33  I not only optimize the performance of concurrency, but also add some new things.
    34  
    35  Like Do(), Intrange(), Uniform(), Sample(), ReadBytes(), Triangular()...
    36  
    37  They are quite similar with the Python Standard libray.
    38  
    39  Exclude Do().
    40  
    41  What does Do use for?
    42  
    43  In some cases, we might call Int(), Intn() multiple times.
    44  
    45  Like
    46  ```
    47  n := rand.Intn(5)
    48  for i :=0; i < n; i++ {
    49      randseed := rand.Int()
    50  }
    51  ```
    52  
    53  If using a global mutex, locking and unlocking cost too much, that's not good.
    54  
    55  However, if we can get a lockless one from the pool, and generate it multiple times.
    56  
    57  There's no cost of locks.
    58  
    59  That's the Do() do.
    60  
    61  ```
    62  Do(func (r *rand.Rand) {
    63      // No more lock here
    64      n := r.Intn(5)
    65      for i :=0; i < n; i++ {
    66          randseed := r.Int()
    67      }
    68  })
    69  
    70  ```
    71  
    72  
    73  # Benchmark
    74  
    75  ```
    76  goos: windows
    77  goarch: amd64
    78  pkg: github.com/MeteorsLiu/lockfree-rand
    79  cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
    80  BenchmarkInt-8                          247086846                4.794 ns/op           0 B/op          0 allocs/op
    81  BenchmarkGoInt-8                        73754803                16.29 ns/op            0 B/op          0 allocs/op
    82  BenchmarkReadSmall-8                     1595437               759.7 ns/op             0 B/op          0 allocs/op
    83  BenchmarkGoReadSmall-8                   1356376               887.3 ns/op             0 B/op          0 allocs/op
    84  BenchmarkReadMedium-8                      49314             24041 ns/op               0 B/op          0 allocs/op
    85  BenchmarkGoReadMedium-8                    43911             27435 ns/op               0 B/op          0 allocs/op
    86  BenchmarkReadLarge-8                       12649             97187 ns/op               0 B/op          0 allocs/op
    87  BenchmarkGoReadLarge-8                     10000            110534 ns/op               0 B/op          0 allocs/op
    88  BenchmarkParallel-8                      4934991               253.0 ns/op            16 B/op          1 allocs/op
    89  BenchmarkGoParallel-8                    4218584               282.6 ns/op            16 B/op          1 allocs/op
    90  BenchmarkParallelRead-8                  4548276               258.9 ns/op            16 B/op          1 allocs/op
    91  BenchmarkGoParallelRead-8                2720745               443.8 ns/op            17 B/op          1 allocs/op
    92  BenchmarkWyhashParallelRead-8            3443152               341.4 ns/op            24 B/op          1 allocs/op
    93  BenchmarkWyhashPoolParallelRead-8        3987759               300.0 ns/op            48 B/op          1 allocs/op
    94  BenchmarkGoMultipleDo-8                  1210926               995.7 ns/op            18 B/op          1 allocs/op
    95  BenchmarkMultipleDo-8                    4430743               276.3 ns/op            16 B/op          1 allocs/op
    96  ```
    97  The prefix of BenchmarkGo stands for **math/rand** function, without which, it stands for this repo.
    98  
    99  Optimized for high concurrent cases, I use sync.Pool to avoid the global mutex lock.