Reputation: 6095
I came across a strange problem today that i could understand the reason. Take the following console program.
internal class Program
{
private static void Main(string[] args)
{
string s1 = GenerateRandomCode(8);
string s2 = GenerateRandomCode(8);
string s3 = GenerateRandomCode(8);
}
public static string GenerateRandomCode(int length)
{
string charPool = "ABCDEFGOPQRSTUVWXY1234567890ZabcdefghijklmHIJKLMNnopqrstuvwxyz";
StringBuilder rs = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++)
{
rs.Append(charPool[(int)(random.NextDouble() * charPool.Length)]);
}
return rs.ToString();
}
}
If i put a breakpoint at the of the program and run the program the values of s1, s2, s3 are all the equal. Now if i put a breakpoint at s2 for example the value returned will be different.
Seems like some kind of concurrency issue? What's going on?
Thanks
Upvotes: 0
Views: 456
Reputation: 48570
Reason: Random number instances when not given any seed value take DateTime.Now.Ticks
value as seed value. Since yours instance is getting recreated in a very quick successions, the instance gets seeded with same ticks. Hence the same random number.
Proof: Put some break-points in the code. Then you will get real random values because when it will strike a debugger, there will be a loss of time till you press F10 or F11 or F5. causing time lapse.
Solution: Create a static instance of Random class and use its Next function whereever you want.
Upvotes: 0
Reputation: 26792
Random number generators are in fact not fully random: given the same seed value, multiple instances will generate the same random sequence.
Couldn't say it better than the MSDN documentation for the Random constructor
"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."
So, in your case you need to keep the Random instance as a class-level field or a function parameter, and instantiate it only once.
Upvotes: 2
Reputation: 15091
Pull the new Random()
call outside of GenerateRandomCode
.
Since you are recreating it each time and calling it in rapid succession, it might be getting the same random seed value.
You can make it static, or use Dependency Injection (pass it in).
I believe that will resolve the problem.
Upvotes: 1
Reputation: 8694
Because you instantiate a new Random
in each call to GenerateRandomCode
and because the calls take very little time, all 3 Random
objects end up with the same time-based seed, which means they'll all return the same first value. Create a field for your Random
object, instantiate it just once at the start of your program, and have GenerateRandomCode
use that instance of Random
instead - you'll now get different values when you call random.NextDouble()
.
Upvotes: 1