C#的Random.Next突然停止返回随机值

6
可能是重复问题:System.Random keeps on returning the same value
我正在重构并扩展一个小的C#基于代理的模型,帮助一些生物学教授预测疾病的传播。在模拟的每一年中,每个个体代理会随机旅行到附近的人口节点,可能会传播疾病。我是C#的新手,但我已经了解到如果使用相同的系统时间重新初始化Random.Next,则可能存在返回相同值的潜在问题。为了避免这种情况,我创建了一个静态实例,每次需要新的随机值时引用它。
具体来说:
在我尝试扩展模型时,我将其更改为并行计算每个人口节点的“旅行”信息。在测试模型时,我注意到在新版本中,疾病不会传播到第一年之后。进一步的调查将问题缩小到节点之间的旅行。在第一年之后,所有代理都保持不动。我检查了负责它们旅行的函数,并发现它通过创建所有附近节点的列表、生成随机数<=列表中元素的数量,并前往listOfNearbyNodes [myRandomNumber]来工作。
问题:
然后我添加了一个打印语句,以输出每个迭代的随机索引值。我发现在模拟的第一年中,整个模型都按预期工作,随机数在可接受的范围内生成。然而,在第一年结束并且模拟循环之后,完全相同的代码仅返回0的“随机”索引。每个线程、每个迭代、每个节点、每个代理,总是0。由于代理的当前节点始终是列表中的第一个项目,因此代理再也不移动了。
我认为这可能是系统时间种子错误的另一种表现,因此我尝试了三种不同的实现静态随机对象的方法,但它没有帮助。每次运行模拟时,第一年总是正确工作,然后Random.Next()开始只返回0。
有人有想法吗?我应该从哪里寻找错误?谢谢!

2
一个简短但完整的代码示例可以帮助您和 Stack Overflow 社区诊断问题。 - LBushkin
我问了一个问题,我认为它是相关的并且可能有所帮助:https://dev59.com/eU7Sa4cB1Zd3GeqP0RLE - Mathias
4个回答

21

我怀疑你正在多个线程中同时使用同一个实例的Random。不要这样做——它不是线程安全的。

选项:

  • 为每个线程创建一个新实例的RandomThreadStatic可以帮助实现)
  • 只使用一个Random实例,但始终在锁定中使用。

我在博客文章中提供了一些示例代码,但请仔细阅读评论,因为那里有改进建议。我计划在不久的将来撰写另一篇有关随机性的文章......


6
我不认为Random类被设计成线程安全的(可以同时在多个线程中使用) - 因此,如果您以这种方式共享单个实例,则可能会破坏随机生成器的状态,从而防止其正确运行。您可以将持有对Random类引用的静态变量装饰为ThreadStatic,这将允许您在每个线程中维护一个单独的实例:
[ThreadStatic]
private static Random m_Random;  // don't attempt to initialize this here...

public void YourThreadStartMethod()
{
    // initialize each random instance as each thread starts...
    m_Random = new Random();
}

如果您正在使用.NET 4.0,还有ThreadLocal<T>类,可以帮助更轻松地使每个线程初始化一个实例。


2

Random 对象不是线程安全的。为了解决这个问题,你可以使用从这个答案抄袭的代码:

class ThreadSafeRandom 
{ 
    private static Random random = new Random(); 

    public static int Next() 
    { 
       lock (random) 
       { 
           return random.Next(); 
       } 
    } 
}

您也可以使用RNGCryptoServiceProvider,它是线程安全的,同时产生更好的随机数据。



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接