This question already has answers here:
Is C# Random Number Generator thread safe?
(17 answers)
Closed 9 years ago.
Ok. Here is what I know that won't work:
int Rand()
{
//will return the same number over and over again
return new Random().Next();
}
static Random rnd=new Random();
int Rand()
{
//if used like this from multiple threads, rnd will dissintegrate
//over time and always return 0
return rnd.Next();
}
This will work correctly, but if used by multiple threads, the CPU usage goes way up, which I don't want, and which I think is not necessary:
int Rand()
{
lock(rnd)
{
return rnd.Next();
}
}
So, is there a thread-safe Random class for c#, or a better way to use it?
I use something like this:
public static class StaticRandom
{
static int seed = Environment.TickCount;
static readonly ThreadLocal<Random> random =
new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed)));
public static int Rand()
{
return random.Value.Next();
}
}
readonly ThreadLocal<Random> random =
new ThreadLocal<Random>(() => new Random(GetSeed()));
int Rand()
{
return random.Value.Next();
}
static int GetSeed()
{
return Environment.TickCount * Thread.CurrentThread.ManagedThreadId;
}
(shamelessly stolen from the comment of Jeroen Vannevel)
I think what you want is threadstatic
[ThreadStatic]
static Random rnd=new Random();
int Rand()
{
if ( rnd == null )
{
rnd = new Random()
}
//Now each thread gets it's own version
return rnd.Next();
}
That way each thread get their own version of your rnd property
The reason your locking will increase cpu usage is because all threads will wait on that single point (should only be an issue if you use it a lot)
[Update] i fixed the initialization. As someone pointed out it does leave the fact that if you start multiple threads in the same milisecond then they will produce the same results.
My group recently looked into this. We came to the conclusion that we should use a random number generator that has been specifically designed to support parallel computing. Tina's Random Number Generator Library (http://numbercrunch.de/trng/) has a stable implementation, and a manual with a theoretical introduction and references to the relevant literature. So far, we are very satisfied with it.
Related
I had a complex scenario when I was using a yield with random numbers and faced some strange behavior.
I tried to simplify my case with a simpler code example and managed to reproduce it with a very simple code.
In the following code, I would expect to get "Equal!" printed, but actually, it is not.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleAppSample
{
static class Program
{
public static void Main(string[] args)
{
IEnumerable<int> randomNumbers = GetRandomNumbers();
int firstRandomnumber = randomNumbers.First();
if (firstRandomnumber == randomNumbers.First())
{
Console.WriteLine("Equal!");
}
}
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static int RandomNumber(int min, int max)
{
lock (syncLock)
{
return random.Next(min, max);
}
}
private static IEnumerable<int> GetRandomNumbers(int loopCount = 2)
{
for (int i = 0; i < loopCount; i++)
{
yield return RandomNumber(int.MinValue, int.MaxValue);
}
}
}
}
I tried to debug it and found even something weirder. While holding the breakpoint at the same place the values of the randomNumbers variable change every moment.
In the following image, you can see the watch shows different numbers for the same variable.
If I change the GetRandomNumbers() method implementation to insert values into a list and return the list (without using yield), it will work fine.
I try to understand why it works this way? I guess it is related to the way random generates numbers based on the computer clock and the way yield works, but I am not sure.
yield means that the collection is not saved but essentially calculated when needed, namely each time you iterate the collection. Thus, each time new Random().Next() is called which may or may not give you a different result, depending on the time between those calls.
Thus, I would suggest the following changes:
If you want to see the same collection contents everytime, save the collection (for example, into a List as you suggested)
If you want to have multiple random numbers, keep the Random instance, if necessary in a static field. Creating a new instance will calculate a new seed based on the current system time and that may be the same, if you create two instances before Windows refreshes the system time.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
This is really weird, and I cannot see why this is happening. In the foreach cycle, I am iterating through a class A collection, and for each class, I call the Count() method, where r1 and r2 numbers are generated from range [-1,1]. The problem is that Random.Next returns the same "random" numbers for each instance. When the results for the first instance are 0 and -1, the same ones will be returned from following instances. Please, could you tell me why this is happening? Also, I cannot get different results in each class A instance. This is the code:
class a
{
Random rnd = new Random();
private void Count()
{
int r1 = rnd.Next(-1, 1);
int r2 = rnd.Next(-1, 1);
}
}
class b
{
List<a> listofA=new list<a>();
foreach (a ACLASS in listofA)
{
ACLASS.Count();
}
}
The problem is that you are creating instances of the Random class too close in time.
When you create a Random object, it's seeded with a value from the system clock. If you create Random instances too close in time, they will all be seeded with the same random sequence.
Create a single Random object and pass its reference to the constructor when you create instances of the "a" class, instead of creating one Random object for each "a" instance.
Use a single, static Random number generator for all instances of the class.
class a
{
private static Random rnd;
static a() {
rnd = new Random();
}
private void Count()
{
int r1 = rnd.Next(-1, 2);
int r2 = rnd.Next(-1, 2);
}
}
Note the change to give you numbers in the range -1,1 rather than -1,0
You're creating new instances of Random very close together (your loop is very tight) so each instance is effectively using the same seed value.
A better approach would be to create one instance and pass that to your Count method.
You probably know this next bit, but I'll include it here for completeness:
The MSDN has the details on this, but basically your problem is the Random.Next method you're using generates:
A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.
because of this your calls will return -1 or 0.
You include a random instance for each A instance. It sounds like they're all getting the same default seed value. You probably want to make a static random for all A instances and use it repeatedly, or alternatively provide a seed value to the Random() instance in the A constructor.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 6 years ago.
I have a class:
public class MyClass
{
public int MyMethod()
{
Random rand = new Random();
return rand.Next() % 10 + 1;
}
}
And 2 objects of it:
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
The problem is that obj1.MyMethod() == obj2.MyMethod() always. Why does it happen? What's the best way to avoid it?
Create your random object static
public class MyClass
{
public static Random rand = new Random();
public int MyMethod()
{
return rand.Next() % 10 + 1;
}
}
Random works on System.DatTime.Now.Ticks.
If we do like this
Random rand = new Random();
internally it happens as
Random rand = new Random(System.DateTime.Now.Ticks);
Just think for a moment the only thing which is not constant in system is System Time.
When ever using Random class make its object once and use its method Next() where ever you want. You will find this situation in loops when random object is created inside loops.
In your code they are created one after another, they get created by same Ticks seed value.
Create your random object static and then they won't be same.
you are creating a new Random every time. When you create a new instance of Random without explicitly specifying the seed value it uses System.DatTime.Now.Ticks as the seed. Due to the speed of calls they are happening at the same 'Tick' so the same seed value is used. As all Random instances generate the exact same sequence of 'random' number for the same seed value the same 'random' value is generated by both instances.
This has been covered many times before on the site and you should search for one of those answers.
But basically you need to create your Random object once and reuse it. This could be done statically , or at least as a class variable.
You should read this question and its answers to find a better approach.
To clarify, multiple students objects and all of them are getting the same value.
I know this question has been asked before, but I have had no luck with the other posts about his topic. I have a random number generator ranging from 1-3. I then us %2 to make a bool value true or false. Every time I run the program I either get all true or all false. Here is my code. I know that random is not really random. What can I do to get more random numbers.
Random random = new Random();
public Student()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
public bool readingLevel()//this always returns one value for the entire program.
{
return level;
}
You are only assigning a random value to 'level' once during the constructor, so it will always have the initial value.
Try:
public bool readingLevel()
{
return (random.Next(1,3) % 2 == 0);
}
Edit:
Static Random random = new Random();
...
It looks like you're trying to get a random number!
Clippy
Well you can try something like this:
static Random random = new Random();
public Student()
{
lock (random)
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
}
public bool readingLevel()//this always returns one value for the entire program.
{
return level;
}
The problem with your snippet seems to be that you are instantiating a new Random class with each of your class instances.
This is not the way Random is supposed to be used, but instead a single Random class instance should be used for acquiring multiple random numbers.
The Rationale for this is that Random in .Net uses a pseudo random algorithm based on state (a seed) that changes every time you ask for a new random number. By instantiating multiple random classes in a relatively short time span, there is a high chance that all of them will be initiated with the same seed (Based on system time) and all will give the same random number.
It looks like your random generator is an instance variable of the Student. Since the generator uses the current time as the seed, if you create a bunch of students within a short time, they will all have each have a generator with the same seed and the same results. You could make the random generator a static variable or, better yet, use constructor injection and pass the level into the Student's constructor.
class Student
{
private static Random random = new Random();
public Student()
{
level = random.NextDouble() < 0.5;
}
public bool readingLevel()
{
return level;
}
}
or use constructor injection so your student class is deterministic.
class Student
{
private boolean level;
public Student(boolean readingLevel)
{
this.level = readingLevel;
}
public boolean readingLevel()
{
return level;
}
}
Create only one instance of Random and reuse it. Creating multiple instances of random in quick succession seeds to the same value and thus leads to the same sequence.
If your code in single threaded you can simply use a static property to hold the instance of Random.
The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to the Random(Int32) constructor. For more information, see the Random(Int32) constructor.
http://msdn.microsoft.com/en-us/library/h343ddh9.aspx
public Student()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
seems very much like a constructor for the Student class. In this constructor you are basically calculating a random number and storing it inside the level field. So if you use the same instance of Student throughout your entire program and call the readingLevel() method multiple times on this instance it will obviously return the same value -> the one that was done during the construction of this instance and that you stored in the level field.
So you might consider moving the random number generation logic into the readingLevel() method instead of simply returning the same value over and over again:
public class Student
{
private Random random = new Random();
public bool readingLevel()
{
int randomLevel = random.Next(1,3);
return (randomLevel % 2 == 0);
}
}
Now everytime you call this method on the same instance you should get a new calculation of a random number.
Some others have said this, but I think the point deserves underscoring with an example.
public class Student
{
Random random = new Random();
public Student()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
public bool readingLevel()//this always returns one value for the entire program.
{
return level;
}
}
public class Program
{
public static void Main()
{
var students = new List<Student>();
for (int i = 0; i < 10; i++)
students.Add(new Student());
//Now you have 10 Students; each Student has its own random number generator
//The generators were created within microseconds of each other, so they most likely have THE SAME SEED
//Because they have the same seed, they will generate identical sequences of numbers
//Each student's reading level is calculated from the first call to .Next(1, 3) on its own RNG.
//The RNGs have the same seed, so each will return the same value for the first call to .Next(1, 3)
//Therefore, all students will have the same reading level!
}
}
You are using random to simulate a true/false situation, so you are trying to limit the result to either 1 or 2. Given that you are doing an odd/even test on the result you might be better off doing:
int randomLevel = random.Next();
level = (randomLevel % 2 == 0);
Also If you create all your students in quick succession there's a good chance that your current code will return the same value for subsequent calls.
Well.
Consider what is happening here. When your Student is constructued, you get some random number, and then set it to the member variable level.
Then, at some other point, you call a function, readingLevel, which returns this previously set value.
Then, you may ponder to yourself: Exactly when would this function give a different value? Well, it will only do so when level gets a different value. And when does that happen? Well, it only happens in the constructor, so, that means, it never happens again for the life of the object ....
Try the following. Move the selection of the random level to the readingLevel function.
Random random = new Random();
public Student()
{
}
public bool readingLevel()//this always returns one value for the entire program.
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
return level;
}
That is because you are using the random.Next() and the level evaluation within the constructor of your class, remember that the constructor is only executed when you create a new instance of your object, for having it executed several times create a different method where you call the random and the level evaluation, that way you'll get different values every time or use Something like this:
public bool Level()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
return level;
}
Random random = new Random(DateTime.Now.Ticks);
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
This is really weird, and I cannot see why this is happening. In the foreach cycle, I am iterating through a class A collection, and for each class, I call the Count() method, where r1 and r2 numbers are generated from range [-1,1]. The problem is that Random.Next returns the same "random" numbers for each instance. When the results for the first instance are 0 and -1, the same ones will be returned from following instances. Please, could you tell me why this is happening? Also, I cannot get different results in each class A instance. This is the code:
class a
{
Random rnd = new Random();
private void Count()
{
int r1 = rnd.Next(-1, 1);
int r2 = rnd.Next(-1, 1);
}
}
class b
{
List<a> listofA=new list<a>();
foreach (a ACLASS in listofA)
{
ACLASS.Count();
}
}
The problem is that you are creating instances of the Random class too close in time.
When you create a Random object, it's seeded with a value from the system clock. If you create Random instances too close in time, they will all be seeded with the same random sequence.
Create a single Random object and pass its reference to the constructor when you create instances of the "a" class, instead of creating one Random object for each "a" instance.
Use a single, static Random number generator for all instances of the class.
class a
{
private static Random rnd;
static a() {
rnd = new Random();
}
private void Count()
{
int r1 = rnd.Next(-1, 2);
int r2 = rnd.Next(-1, 2);
}
}
Note the change to give you numbers in the range -1,1 rather than -1,0
You're creating new instances of Random very close together (your loop is very tight) so each instance is effectively using the same seed value.
A better approach would be to create one instance and pass that to your Count method.
You probably know this next bit, but I'll include it here for completeness:
The MSDN has the details on this, but basically your problem is the Random.Next method you're using generates:
A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.
because of this your calls will return -1 or 0.
You include a random instance for each A instance. It sounds like they're all getting the same default seed value. You probably want to make a static random for all A instances and use it repeatedly, or alternatively provide a seed value to the Random() instance in the A constructor.