Irregular updates


Go Gotcha: math/rand Thread Safety Isn’t Universal

Ran into a subtle trap with Go’s math/rand package regarding concurrency. It’s easy to assume all random generation is thread-safe, but that’s not quite right.

The Key Difference:

  • rand.Intn() (Package Level): Thread-safe! Uses a global source with an internal mutex. Good for most concurrent uses.
  • myRand.Intn() (Method on *rand.Rand): NOT thread-safe by default! If you create your own *rand.Rand instance (myRand) and share it between goroutines, calling its methods concurrently without your own locking will cause data races.

Example I Encountered:

func (wl *IotWorkload) RandomValue() string {
    // Unsafe if wl.r (*rand.Rand) is shared by goroutines without locking:
 // value := wl.r.Intn(10000) 

    // Safe - uses the package-level, locked global source:
 value := rand.Intn(10000) 

 return util.ToString(value)
}

Using wl.r.Intn() looked fine initially, but it’s a concurrency bug waiting to happen if wl.r is shared. Switching to the package-level rand.Intn() was the safe fix here.

Lesson: For simple concurrent needs, stick to the package-level rand.Intn(). If you manage your own *rand.Rand instance across goroutines, remember you need to add the necessary sync.Mutex or other synchronization. Don’t get caught out!