Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the random number generator in Haskell thread-safe?

Is the same "global random number generator" shared across all threads, or does each thread get its own?

If one is shared, how can I ensure thread-safety? The approach using getStdGen and setStdGen described in the "Monads" chapter of Real World Haskell doesn't look safe.

If each thread has an independent generator, will the generators for two threads started in rapid succession have different seeds? (They won't, for example, if the seed is a time in seconds, but milliseconds might be OK. I don't see how to get a time with millisecond resolution from Data.Time.)

like image 207
zoo Avatar asked Aug 22 '11 20:08

zoo


People also ask

Is random number generator thread-safe?

Random are thread-safe. However, the concurrent use of the same java. util. Random instance across threads is synchronized and as we have found out tends to trigger contention issues affecting performance of the application.

Is Rand function thread-safe?

The function rand() is not reentrant or thread-safe, since it uses hidden state that is modified on each call.

Is random class thread-safe?

random() guarantees it's safe for use by multiple threads. But the Random class does not.

Why is random not thread-safe?

This is due to an implementation detail of Random that does not tolerate multithreaded access (it wasn't designed for it, and the docs explicitly call out that Random should not be used from multiple threads, as they do for most types in the . NET Framework). // over with the new number.


2 Answers

There is a function named newStdGen, which gives one a new std. gen every time it's called. Its implementation uses atomicModifyIORef and thus is thread-safe.

newStdGen is better than get/setStdGen not only in terms of thread-safety, but it also guards you from potential single-threaded bugs like this: let rnd = (fst . randomR (1,5)) <$> getStdGen in (==) <$> rnd <*> rnd.

In addition, if you think about the semantics of newStdGen vs getStdGen/setStdGen, the first ones can be very simple: you just get a new std. gen in a random state, chosen non-deterministically. On the other hand, with the get/set pair you can't abstract away the global program state, which is bad for multiple reasons.

like image 195
Rotsor Avatar answered Oct 03 '22 15:10

Rotsor


I would suggest you to use getStdGen only once (in the main thread) and then use the split function to generate new generators. I would do it like this:

Make an MVar that contains the generator. Whenever a thread needs a new generator, it takes the current value out of the MVar, calls split and puts the new generator back. Due to the functionality of an MVar, this should be threadsafe.

like image 33
fuz Avatar answered Oct 03 '22 17:10

fuz