Reputation: 705
The documentation for the standard-library rand.NewSource
function states that,
Unlike the default Source used by top-level functions, this source is not safe for concurrent use by multiple goroutines.
Is there a way to create a thread-safe rand.Source
?
Context: I have a type with a method that may be called by multiple go-routines, and this method uses random numbers. I want to support dependency injection for testing, so I can't use the default Source.
Upvotes: 4
Views: 7030
Reputation: 121059
It's typical to use a sync.Mutex to ensure that a value or values are not accessed concurrently. Here's how to use a sync.Mutex to protect a rand.Source:
var s = rand.NewSource(seed)
var mu sync.Mutex
// lock/unlock when accessing source from a goroutine
mu.Lock()
i := s.Int63()
mu.Unlock()
The rand.Rand does not support concurrent use. If the application is using the rand.Source to create a rand.Rand, then protect the rand.Rand instead:
var r = rand.New(rand.NewSource(seed))
var mu sync.Mutex
// lock/unlock when accessing the rand from a goroutine
mu.Lock()
i := r.Int()
mu.Unlock()
The mutex used to protect the rand.Rand will also protect the rand.Source.
Upvotes: 8
Reputation: 705
After some sleuthing, I learned that the way to go is to protect the Source with a mutex. The standard library even contains an implementation, lockedSource
, but the relevant type is not exported.
Upvotes: 2