This question comes from the knowledge that when new Random() is called very quickly it gets seeded with the same value which I assume is based on DateTime.Now.Ticks.
Suppose you had a high traffic web application on latest versions ASP.NET, IIS, .NET, etc.. which implements an online casino. I would think the simulated slot machines need to pull from a single random number stream.
With high volume situation you might get two slot machines with the same random number generator causing too many big jackpots. I don’t have a full understanding of pseudorandom generators but my intuition is that to safely implement an online casino you really need to pull from a single generator that is seeded just once.
One solution I can think of is a synchronized queue with a single thread that pushes the numbers on, but I wouldn’t know how to synchronize it across a multi-site application.
Is there a good/standard solution to this scenario?
Update: the actual scenario I’m working on (which really has no chance of getting enough volume to cause a problem)
My real-world situation is that I have a moderately high traffic asp.net web forms site and the requirement to show one of two user controls on each request. I did so with the following code:
// Randomly display one of (FreeCreditScore1, MyFreeScoreNow1)
private void ShowCreditScoreAd()
{
FreeCreditScore1.Visible = (new Random().Next(2) == 1);
MyFreeScoreNow1.Visible = !FreeCreditScore1.Visible;
}
If I unit test the above code by calling it in rapid succession it fails and I came to understand the reason was that new Random() was getting called in the same “tick”.
That said, I do believe my current implementation is sufficient (feel free to correct me) but I was curious how it could be solved if I really wanted to be strict about it…
Just protect the random number generator with a lock. Unless you’re making hundreds of thousands of calls per second to it, it’s going to be plenty fast enough.
Before you say, “locks are too slow,” note that I tested this on an old 2.4 GHz quad core. It took approximately 70 nanoseconds to get a random number when the lock isn’t contended. Lock contention can kill performance, but you’d need lots of requests.
In a Web app, you’d want to initialize one of those in
Application_Start, and make that singleton available to the rest of your application.There are faster ways, but they’re more difficult to implement. One way would be to pre-generate millions of random numbers (call
Random.NextBytes) and store them in a buffer. Protect that with a reader/writer lock. When the number of values remaining reaches some threshold, the thread grabs the writer lock, preventing all other access until it refills the buffer. This is probably the way you’d want to go if you’re using some other source of random numbers. For example theRNGCryptoServiceProvider.GetBytesmethod (http://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.getbytes.aspx).