Don’t seed the global random in your package
Go has a global random generator that is used when you call functions in the
math/rand
package.
As of go1.6
, the global random generator is seeded to the same value at the
start of every program, which
means that a deterministic sequence of numbers is returned every time the
program is run.
The Seed
function allows you to introduce randomness by seeding the
underlying source.
rand.Seed(time.Now().UnixNano())
However, calling rand.Seed()
modifies the global random that other packages
or client programs where your package is being imported into also have access
to. If the other packages or client programs also seed the random generator
concurrently, it could lead to panics.
So it may be wise to create your own private random number generator. In
addition, if the random generator may be used from more than one goroutine, you
should make it goroutine safe. Add a file random.go
to your package:
package bar
import (
"math/rand"
"sync"
"time"
)
var random *rand.Rand
func init() {
random = rand.New(
&lockedRandSource{
src: rand.NewSource(time.Now().UnixNano()),
},
)
}
// locked to prevent concurrent use of the underlying source
type lockedRandSource struct {
lock sync.Mutex // protects src
src rand.Source
}
// to satisfy rand.Source interface
func (r *lockedRandSource) Int63() int64 {
r.lock.Lock()
ret := r.src.Int63()
r.lock.Unlock()
return ret
}
// to satisfy rand.Source interface
func (r *lockedRandSource) Seed(seed int64) {
r.lock.Lock()
r.src.Seed(seed)
r.lock.Unlock()
}
Now, use you can use random
, the private random generator, to generate random
numbers for use in your package. This is the approach I use in
go-xkcd, an xkcd API client.