github.com/CAFxX/fastrand@v0.1.0/splitmix64_sharded.go (about)

     1  package fastrand
     2  
     3  import (
     4  	"runtime"
     5  	"unsafe"
     6  )
     7  
     8  const cacheline = 64
     9  
    10  // ShardedSplitMix64 implements the Java 8 SplittableRandom generator with per-thread (per-P) states.
    11  //
    12  // This generator is safe for concurrent use by multiple goroutines.
    13  // The zero value is a valid state, but it uses a static, all zero seed: use NewShardedSplitMix64 to instantiate a ShardedSplitMix64 with a random seed.
    14  type ShardedSplitMix64 struct {
    15  	states   []paddedSplitMix64
    16  	fallback AtomicSplitMix64
    17  }
    18  
    19  type paddedSplitMix64 struct {
    20  	SplitMix64
    21  	_ [cacheline - unsafe.Sizeof(SplitMix64{})%cacheline]byte
    22  }
    23  
    24  // NewShardedSplitMix64 creates a valid ShardedSplitMix64 instance seeded using crypto/rand.
    25  //
    26  // Increasing the value of GOMAXPROCS after instantiation will likely yield sub-optimal performance.
    27  func NewShardedSplitMix64() *ShardedSplitMix64 {
    28  	r := &ShardedSplitMix64{
    29  		states: make([]paddedSplitMix64, runtime.GOMAXPROCS(0)),
    30  	}
    31  	for i := range r.states {
    32  		r.states[i].Seed(Seed())
    33  	}
    34  	r.fallback.Seed(Seed())
    35  	return r
    36  }
    37  
    38  // Uint64 returns a random uint64.
    39  //
    40  // This function is safe for concurrent use by multiple goroutines.
    41  func (r *ShardedSplitMix64) Uint64() uint64 {
    42  	l := len(r.states) // if r is nil, panic before procPin
    43  	id := procPin()
    44  
    45  	if fastrand_nounsafe || l <= id {
    46  		procUnpin()
    47  		return r.fallback.Uint64()
    48  	}
    49  
    50  	n := r.states[id].Uint64()
    51  	procUnpin()
    52  	return n
    53  }