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.

n := rand.Int()

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 // your private random

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.

 
50
Kudos
 
50
Kudos

Now read this

Parallel tests in Go

Go surprises me with how simple it makes things. Today, it was parallel testing. In other languages I’ve used, it may require third-party packages, require complicated syntax, or may just not be possible. In Go, it’s as simple as: import... Continue →