You could use a sync.Pool for this:
https://golang.org/pkg/sync/#Pool
- you can use it to make a pool of *rand.Rands which automatically
resizes to match your concurrency load.
Alternatively, if you want more control over the process: make a
buffered chan *rand.Rand (no need to put anything in it.) When you
need a Rand, use a nonblocking read to get an existing one if
possible, and if not, initialize one. When you're done, use a
nonblocking write to put it back into the chan (and drop it if the
channel is full.) You can monitor how many times you hit the "drop it
if the channel is full" branch if you want to know if the channel
buffer is too small for your load.
Since *rand.rngSource objects are pretty big (607 int64s and 2 ints; a
little under 5K), you'll want to keep the number of extra sources you
keep around to a minimum.
Or you could implement a concurrency-safe rand.Source implementation.
That seems tricky to do correctly, so it's probably better to do the
pooling above unless you're seriously memory constrained.