This question already has answers here:
Random String Generator Returning Same String [duplicate]

(30个答案)



Why do I keep getting two of same random values in this code? [duplicate]

(5个答案)


6年前关闭。



Task.Factory.StartNew(() =>
    {
    new Class1();
    })

Task.Factory.StartNew(() =>
    {
    new Class2();
    })

在class1和class2的构造函数中,我有:
var timeout = new Random().Next(0, 5000);
Debug.Print(timeout.ToString());

在两个类中,随机值“超时”始终相同。我不明白为什么。

如果我在创建任务之间添加了暂停,则不一样。

编辑:

我不明白这与“Random String Generator Returning Same String”有何关系。

他们正在方法中创建随机实例。我在完全不同的任务中称呼它,因此它们应该彼此独立。

最佳答案



尽管根本原因是相同的,但它并不直接相关。一个更好的副本是这个问题:Why do I keep getting two of same random values in this code?

它包含new Random的功能an explanation –由documentation提供:



换句话说:如果快速连续创建Random对象,它们将产生相同的随机数序列。



这些对象是否在不同的线程(或Task)中创建是无关紧要的-它们仅取决于创建它们时的系统时间,而无其他依赖。正如您所说,它们实际上彼此独立。但是它们都依赖于相同的种子值,即创建时的系统时间。

解决此的正确方法通常是仅包含Random类的一个实例。 –实际上,这样的代码是:new Random().Next(…)是代码气味,因为它滥用了Random类:您不应该为每个调用都生成一个新实例;相反,您应该重用同一实例来生成一个随机数序列。

不幸的是,您不能简单地在不同的并发任务中使用相同的Random实例,因为relevant method并非线程安全的-也就是说,同时从多个线程中调用它可能导致竞争。有几种解决方法,但是最简单的方法是使用显式锁:

public Class(Random rng) {
    lock (rng) {
        var timeout = rng.Next(5000);
        Debug.Print(timeout.ToString());
    }
}

重要的是要注意,每次对rng的访问都必须被锁定,否则就没有意义了。

现在,您可以创建任务并运行它们,并获得适当的随机性:
var rng = new Random();

var tasks = new [] {
    Task.Run(() => { new Class(rng); }),
    Task.Run(() => { new Class(rng); })
};
Task.WaitAll(tasks);

请注意,当忽略lock(…)块时,您似乎正在获得正确的结果。这是使用并发性和随机性的危险:很难验证您的结果是否正确或在整个过程中是否被破坏。因此,请谨慎行事。

关于c# - 为什么两个彼此创建的任务会生成相同的随机值? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24600937/

10-16 17:21