How to use a random class in a multi-threaded application

I need to use a random class to generate random numbers in a multi-threaded application inside a public static function. How can i achieve this. Currently, the function below works very well, but it is not very fast compared to a random class. Therefore, I need to modify the function below and make it work with a random class, while thousands of simultaneous calls occur with this class. if I use random, then it uses the same seed for every call, I suppose, and randomization is very bad. my current class

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Security.Cryptography; public static class GenerateRandomValue { static RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider(); public static int GenerateRandomValueDefault(int irRandValRange)//default min val 1 { if (irRandValRange == 0) irRandValRange = 1; byte[] randomNumber = new byte[4]; // 4 bytes per Int32 Gen.GetBytes(randomNumber); return Math.Abs(BitConverter.ToInt32(randomNumber, 0) % irRandValRange) + 1; } public static int GenerateRandomValueMin(int irRandValRange, int irMinValue) { byte[] randomNumber = new byte[4]; // 4 bytes per Int32 Gen.GetBytes(randomNumber); return BitConverter.ToInt32(randomNumber, 0) % irRandValRange + irMinValue; } } 

Another feature that seems pretty good and reliable in streaming

 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Threading; public static class GenerateRandomValue { private static Random seedGenerator = new Random(); private static ThreadLocal<Random> random = new ThreadLocal<Random>(SeededRandomFactory); private static Random SeededRandomFactory() { lock(seedGenerator) return new Random(seedGenerator.Next()); } public static int GenerateRandomValueMin(int irRandValRange, int irMinValue) { return random.Value.Next(irMinValue, irRandValRange); } } 
+4
source share
4 answers

What you need is the best way to start seeding in your ASP.NET application, the quality of Random should be subtle using the method below.

 public static int GenerateRandomValueDefault(int irRandValRange)//default min val 1 { return GenerateRandomValueMin(irRandValRange, 1); } public static int GenerateRandomValueMin(int irRandValRange, int irMinValue) { Random rand = GetRandom(); return rand.GetNext(irMinValue,irRandValRange) } //This is a global random number generator, it is only used to provide the seed for the local RNG's. private static Random GlobalRandom = new Random(); private static Random GetRandom() { if (HttpContext.Current.Session["RNG"] == null) { //This lock is only hit the very first time the users Session state is used, every time after that it should use the cached local copy without taking the lock. lock(GlobalRandom) { //We use the Global RNG for seed instead of the default because it uses time to seed by default, and if two people get a new Random() within the same time-slice they will have the same seed. This prevents that from happening. HttpContext.Current.Session["RNG"] = new Random(GlobalRandom.Next()); } } //Return the cached/new RNG. return (Random)HttpContext.Current.Session["RNG"]; } 

You have one instance of the global RNG that blocks, however this only happens when a new session state is created, after which the session uses only a local copy. You will get very good runtime performance with little load on the first page per person, since it generates one number from the global repository.

You can change this according to your needs, but it gives you a general idea, but it gives you a general idea.


As suggested by Henk Holterman, this lock-less solution is smaller, which can be faster and does not use HttpState.

 private static int SeedCounter = 0; private readonly object SeedInitLock = new Object(); private static Random GetRandom() { //Do init the first time this function is ever called. if(SeedCounter == -1) { //The first time the function is called everyone will try to update SeedCounter, but only the first //thread to complete it will be the value everyone uses. Random initRNG = new Random(); Interlocked.CompareExchange(ref SeedCounter, initRNG.Next(), -1); } else if (SeedCounter < 0) { //Because Interlocked.Increment wraps the value to int.MinValue and Random(int) will take the absolute //value of the seed, we skip all of the negitive numbers and go to 0. Interlocked.CompareExchange(ref SeedCounter, 0, int.MinValue); } int tempSeed = Interlocked.Increment(ref SeedCounter); if (tempSeed < 0) { //If tempSeed is negative we hit a edge case where SeedCounter wrapped around. We just call the function //again so we do not reuse a seed that was just used. return GetRandom(); } return new Random(tempSeed); } 
+3
source

You did not specify any restrictions other than speed, so I think that Random should do.

 // Field in the class Random rand = new Random(); // Inside a method: int randomValue = rand.Next(); // Random positive integer returned int randomValue = rand.Next(max); // Random under max int randomValue = rand.Next(min, max); // Random in range 
+3
source

I would suggest the System.Web.Security.Membership.GeneratePassword() method.

 string generated = System.Web.Security.Membership.GeneratePassword( 10, // maximum length 3) // number of non-ASCII characters. 
0
source

Using Random with a good seed seems to be "working better." But do you need performance?

Check this blog for indicators: http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx At the end there is a tip about seeding with the provider.

Take it with a piece of salt. You will need to repeat the tests to make sure.

0
source

All Articles