I have a loop that needs to wait a random amount of time before looping again.
What I have:
for {
rand.Seed(time.Now().UnixNano())
r := rand.Int()
//Do stuff
t, _ := time.ParseDuration(string(r) + "ms")
time.Sleep(t)
}
Unfortunately, the loops run multiple times, just like if time.Sleep
was not working.
for
loop doesn't spawn new goroutines unless you do it explicitly in cycle. By default next cycle starts only after previous is done. So you do not need any delay. Just make sure you do not use go
keyword in your cycle.
If you want to launch goroutines:
for {
rand.Seed(time.Now().UnixNano())
r := rand.Int()
//Do stuff in separate goroutine
go DoStuff()
t, _ := time.ParseDuration(string(r) + "ms")
time.Sleep(t)
}
This way new goroutine will be launched.
You should check the error you are currently discarding from t, _ := time.ParseDuration
: the time.Duration
you are passing to Sleep is in its zero value, which causes the function to sleep for 0 nanoseconds.
t, err := time.ParseDuration(string(r) + "ms")
if err != nil {
log.Println(err)
return
}
Resulting in:
time: invalid duration �ms
Since you are directly casting an integer to a string, you are messing with a whole lot of unicode logic you don't really want to.
strconv
: t, err := time.ParseDuration(strconv.Itoa(r) + "ms")
if err != nil {
log.Println(err)
return
}
Result:
time: invalid duration 7936209096285811603ms
You get this error because time.Duration
is represented using a int64
for storing nanoseconds. You are trying to pass an int
representing MILLIseconds: you will be overflowing most of the time.
for {
rand.Seed(time.Now().UnixNano())
r := rand.Int()
log.Println(r)
d := time.Duration(r)
time.Sleep(d)
}
Now it works! The first integer generated by my function is 649508928394582529, which I am casting to time.Duration
(again, this is an int64
of nanoseconds). This is approximatively 649508928 seconds: just over a week.
It looks like a lot. But keep in mind that you were trying to use the generated int
as milliseconds: that is 10^6 times more.
While we are at it, let's polish a bit:
rand.Seed(time.Now().UnixNano())
for {
r := rand.Int()
log.Println(r)
d := time.Duration(r)
time.Sleep(d)
}
Explanation: a pseudorandom number generator is a state machine. You have to feed it a seed once, and then it will work forever. Giving it a different seed every time you run it is not improving its randomness: it's applying the same algorithm over and over on a predictable value (time). You can achieve the same exact degree of randomness by directly using time.Now()Unix()