rand.Intn panic: runtime error: index out of range

1,023 views
Skip to first unread message

buzzlight

unread,
Sep 26, 2015, 10:39:24 PM9/26/15
to golang-nuts
rand.Intn panic  in goroutine, below is stack info

panic: runtime error: index out of range

goroutine 7 [running]:
math/rand.(*rngSource).Int63(0x820200a00, 0x2a4ec0830e6a2d28)
/usr/local/go/src/math/rand/rng.go:244 +0xc1
math/rand.(*Rand).Int63(0x8201e8320, 0x2a4ec0830e6a2d28)
/usr/local/go/src/math/rand/rand.go:46 +0x39
math/rand.(*Rand).Int31(0x8201e8320, 0x2a4ec083)
/usr/local/go/src/math/rand/rand.go:52 +0x21
math/rand.(*Rand).Int31n(0x8201e8320, 0x14, 0x3)
/usr/local/go/src/math/rand/rand.go:87 +0xc1
math/rand.(*Rand).Intn(0x8201e8320, 0x14, 0x3)
/usr/local/go/src/math/rand/rand.go:101 +0x92

code is 

package main

import (
//"io"
"fmt"
"math/rand"
"time"
)

var defaultRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))

func test(index int) {
for i := 0; i < 1000*10; i++ {
_ = defaultRand.Intn(20)
}
fmt.Println("done", index)
}

func main() {
for i := 0; i < 10; i++ {
go test(i)
}

time.Sleep(5 * time.Second)
fmt.Println("exit")
}

it works well when run only one goroutine


main.go

buzzlight

unread,
Sep 26, 2015, 10:45:35 PM9/26/15
to golang-nuts
it works well if call rand.New every times, but performance is bad.


在 2015年9月27日星期日 UTC+8上午10:39:24,buzzlight写道:

Chris Kastorff

unread,
Sep 26, 2015, 10:58:11 PM9/26/15
to buzzlight, golang-nuts
rand.Rand is not safe for concurrent access. Create a new rand.Rand
per goroutine; you don't have to do it on every Intn call, just enough
to avoid concurrent access.

http://play.golang.org/p/vBHatu5Md3
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Dianming Song

unread,
Sep 27, 2015, 10:41:26 PM9/27/15
to Chris Kastorff, golang-nuts
how to create  new Rand pre goroutine in a http server? 

Chris Kastorff

unread,
Sep 27, 2015, 11:17:14 PM9/27/15
to Dianming Song, golang-nuts
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.

Nick Craig-Wood

unread,
Sep 28, 2015, 7:13:16 AM9/28/15
to Chris Kastorff, Dianming Song, golang-nuts
Or you could start a goroutine which pumps random numbers into a
(buffered) channel - that is easy and might work for you.
--
Nick Craig-Wood <ni...@craig-wood.com> -- http://www.craig-wood.com/nick

Clark Wierda

unread,
Jan 5, 2016, 1:14:21 AM1/5/16
to golang-nuts
From the package documentation: The default Source is safe for concurrent use by multiple goroutines.

I understood this to include instances of NewSource as well.  I now know that this is incorrect.  Sources can be safe for concurrent access, but they do not have to be.

I think a note to the effect that NewSource is not inherently safe for concurrent access should be added to its documentation.

Michael Jones

unread,
Jan 5, 2016, 7:08:50 AM1/5/16
to Clark Wierda, golang-nuts
The meta-issue deserves to be clear as well—something dynamic that is concurrency-safe must be serializing internally at a performance cost that is likely to become a performance problem at scale. Something not-safe is “raw” and can run as fast as possible in its lone, non-concurrent context. These two aspects frame the issue.

— 
Michael Jones, CEO  •  mic...@wearality.com  •  +1 650 656-6989 
Wearality Corporation  •  289 S. San Antonio Road  •  Los Altos, CA 94022

Clark Wierda

unread,
Jan 5, 2016, 3:40:16 PM1/5/16
to golang-nuts, cbwi...@gmail.com
I found comments about the concurrency-safe aspect of top-level functions in packages.  Included was a comment that lower-level function in that package should not be considered concurrency-safe unless specifically indicated as such.

This is consistent, provides the capability you address regarding performance, and is in line with my experience with the packages I've used so far.

What I don't know is where this information on the general expectation should be in the Golang documentation.  Since it is more general (and the math/rand package is consistent with the rest), I don't feel a special mention is needed in the package.  [I've done some more research since my earlier post.]  But, as a new user, where would I be expected to have found this information on what I should expect regarding features of the packages and the functions they contain?

Clark B. Wierda
Go student, entering the "know enough to be dangerous" stage
Currently leaning more about performance evaluation and improvement
Reply all
Reply to author
Forward
0 new messages