我正在使用.NET创建一个人工生命程序,我正在使用C#在Singleton中定义的伪随机类。我的想法是,如果我在整个应用程序中使用相同的随机数生成器,我只能保存种子,然后从种子重新加载以重新计算某个有趣的运行。
public sealed class RandomNumberGenerator : Random
{
private static readonly RandomNumberGenerator instance = new RandomNumberGenerator();
RandomNumberGenerator()
{
}
public static RandomNumberGenerator Instance
{
get
{
return instance;
}
}
}
我还想要一种可以给我两个不同随机数的方法。
public static Tuple<int, int> TwoDifferentRandomNumbers(this Random rnd, int minValue, int maxValue)
{
if (minValue >= maxValue)
throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than minValue");
if (minValue + 1 == maxValue)
return Tuple.Create<int, int>(minValue, maxValue);
int rnd1 = rnd.Next(minValue, maxValue);
int rnd2 = rnd.Next(minValue, maxValue);
while (rnd1 == rnd2)
{
rnd2 = rnd.Next(minValue, maxValue);
}
return Tuple.Create<int, int>(rnd1, rnd2);
}
问题是有时候rnd.Next(minValue,maxValue
总会返回minValue
。如果此时断点并尝试创建双精度并将其设置为rnd.NextDouble()
,则返回0.0。任何人都知道为什么会这样吗?
我知道它是一个伪随机数生成器,但坦率地说,我没想到它会锁定为0.从多个线程访问随机数生成器......这可能是问题的根源吗?
编辑:谢谢,问题最终是线程安全。这是该课程的新版本。
public sealed class RandomNumberGenerator : Random
{
private static Random _global = new Random();
[ThreadStatic]
private static Random _localInstance;
RandomNumberGenerator()
{
}
public static Random Instance
{
get
{
Random inst = _localInstance;
if (inst == null)
{
int seed;
lock (_global) seed = _global.Next();
_localInstance = inst = new Random(seed);
}
return _localInstance;
}
}
}
答案 0 :(得分:11)
Random
类不是线程安全的。
您应该制作static
实例[ThreadStatic]
,或使用锁定保护它。
答案 1 :(得分:3)
如果即使保存种子也只使用一个RNG用于多个线程,则下次启动应用程序时将无法生成相同的数字,因为您无法确定对RNG的调用来自不同的线程将以相同的顺序。
如果您有一个固定/已知的线程数,则每个线程生成一个RNG并保存每个种子。
如果您100%确定每个线程将使用与上次使用相同种子时完全相同的顺序调用RNG,请忘记我刚刚说过的内容。
答案 2 :(得分:1)
我的想法是,如果我在整个应用程序中使用相同的随机数生成器,我只能保存种子,然后从种子重新加载以重新计算某个有趣的运行。
为此,您实际上不需要RNG的单例实例。如果您将Random
的两个单独实例初始化为相同的seed
,则它们将生成完全相同的序列。
我的建议是,保存种子,但摆脱单身。
答案 3 :(得分:1)
我甚至不必查看Random类,知道“此类的所有实例方法或不是线程安全的”。这适用于所有.NET类,只有极少数例外。
是的,它是多线程的。但你没有提到验证MaxValue&gt; MinValue也是。