There are often questions on .NET newsgroups such as: "Why am I getting the same numbers
out of Random
time and time again?" When the code involved is posted, it's
almost always something like the following:
using System; class Program { static void Main(string[] args) { for (int i=0; i < 100; i++) { Console.WriteLine (GenerateRandomNumber()); } } static int GenerateRandomNumber() { // Bad code! Do not use! Random rng = new Random(); return rng.Next(); } } |
So, what's wrong with it? Well, when you create an instance of Random
, it uses
a seed to work out where to start. If you use the same seed value twice, you'll get the same
sequence of random numbers. When you use the parameterless constructor (as tends to be the case),
Random
uses the current time as the seed. The code above creates several instances
in very quick succession, and "the current time" tends to have a granularity of at least 10ms, so
many instances will share the same seed and thus create the same sequence of numbers.
The usual answer is to create a single instance of Random
and reuse it. That's
all very well, but it can be a bit unsightly - you end up with one instance of Random
per class which needs to use random numbers, when you really only want a system-wide one. Using
a static member somewhere would seem an obvious answer, but Random
isn't thread-safe.
My suggested solution is to use MiscUtil.StaticRandom
, which is a class composed
entirely of static methods mirroring the ones in System.Random
. Using it is very simple:
using System; using MiscUtil; class Program { static void Main(string[] args) { for (int i=0; i < 100; i++) { Console.WriteLine (StaticRandom.Next()); } } } |
(The call to Next()
can be replaced with NextDouble()
, NextBytes()
etc.
Thread safety is achieved with a simple lock - I experimented with a thread-local instance of Random
,
but found it to be slower than using a lock.
Enjoy!
Back to the main MiscUtil page.