此问题已经在这里有了答案:
Task.Factory.StartNew(() =>
{
new Class1();
})
Task.Factory.StartNew(() =>
{
new Class2();
})
在class1和class2的构造函数中,我有:
var timeout = new Random().Next(0, 5000);
Debug.Print(timeout.ToString());
两个类中的随机值'timeout'始终相同。我不明白为什么。
如果我在创建任务之间添加一个暂停,则不一样。
编辑:
我不知道这与“ Random String Generator Returning Same String”有什么关系。
他们正在方法中创建随机实例。我在完全不同的任务中称呼它,因此它们应该彼此独立。
我不知道这与“返回相同字符串的随机字符串生成器”有什么关系。
虽然根本原因相同,但没有直接关系。一个更好的副本是这个问题:Why do I keep getting two of same random values in this code?
它包含an explanation的功能new Random
–出于documentation的礼貌:
默认种子值来自系统时钟,并且具有有限的分辨率。结果,通过调用默认构造函数紧密连续创建的不同Random对象将具有相同的默认种子值,因此将产生相同的随机数集。
换句话说:如果快速连续创建Random
对象,它们将产生相同的随机数序列。
他正在方法中创建随机实例。我在完全不同的任务中称呼它,因此它们应该彼此独立。
这些对象是否在不同的线程(或 解决这个问题的正确方法Task
)中创建是无关紧要的-它们仅取决于创建它们时的系统时间,而无其他依赖。正如您所说,它们实际上彼此独立。但是它们都依赖于相同的种子值,即创建时的系统时间。Random
类的一个实例。 –实际上,这样的代码是这样的:new Random().Next(…)
是代码异味,因为它滥用Random
类:不应为每个调用都生成一个新实例;相反,您应该重用同一实例来生成sequence随机数。[不幸的是,您不能简单地在不同的并发任务中使用相同的Random
实例,因为relevant method并不是线程安全的-也就是说,同时从多个线程中调用它可能会导致竞争。有几种解决方法,但是最简单的方法是使用显式锁:
public Class(Random rng) {
lock (rng) {
var timeout = rng.Next(5000);
Debug.Print(timeout.ToString());
}
}
需要特别注意的是,必须锁定对rng
的访问权限[[every
,否则就没有意义了。现在您可以创建任务并运行它们,并获得适当的随机性:
var rng = new Random();
var tasks = new [] {
Task.Run(() => { new Class(rng); }),
Task.Run(() => { new Class(rng); })
};
Task.WaitAll(tasks);
注意,当忽略lock(…)
块时,它可能
似乎就像您得到正确的结果一样。这是使用并发性和随机性的危险:很难验证您的结果是否正确或在整个过程中是否被破坏。因此请谨慎行事。