Random 并行循环和随机循环产生奇数结果
我刚开始玩任务并行库,遇到了一些有趣的问题;我对正在发生的事情有一个大致的想法,但我希望听到比我更有能力的人的评论,以帮助理解正在发生的事情。很抱歉代码有点长 我从随机行走的非平行模拟开始:Random 并行循环和随机循环产生奇数结果,random,parallel-processing,simulation,task-parallel-library,Random,Parallel Processing,Simulation,Task Parallel Library,我刚开始玩任务并行库,遇到了一些有趣的问题;我对正在发生的事情有一个大致的想法,但我希望听到比我更有能力的人的评论,以帮助理解正在发生的事情。很抱歉代码有点长 我从随机行走的非平行模拟开始: var random = new Random(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); var simulations = new List<int>(); for (var run = 0; run
var random = new Random();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var simulations = new List<int>();
for (var run = 0; run < 20; run++)
{
var position = 0;
for (var step = 0; step < 10000000; step++)
{
if (random.Next(0, 2) == 0)
{
position--;
}
else
{
position++;
}
}
Console.WriteLine(string.Format("Terminated run {0} at position {1}.", run, position));
simulations.Add(position);
}
Console.WriteLine(string.Format("Average position: {0} .", simulations.Average()));
stopwatch.Stop();
Console.WriteLine(string.Format("Time elapsed: {0}", stopwatch.ElapsedMilliseconds));
Console.ReadLine();
我的猜测是,问题与以下事实有关:随机对象在循环之间共享,并且具有某种状态。“失败的并行”版本在持续时间方面缺乏改进,我认为这是因为对Random的调用不是并行处理的(尽管我看到并行版本使用两个内核,而原始版本没有)。我真的不明白为什么模拟结果是这样的
我的另一个担忧是,如果我使用每个循环的本地随机实例,我可能会遇到多个循环从同一个种子开始的问题(当您在时间上生成多个过于接近的随机数,导致相同的序列时,会遇到这个问题)
任何对正在发生的事情的洞察对我来说都是非常有价值的 随机类不是线程安全的;如果在多个线程上使用它,它可能会出错
您应该在每个线程上创建一个单独的
Random
实例,并确保它们不会使用相同的种子。(例如,Environment.TickCount*Thread.CurrentThread.ManagedThreadId
)这两种方法都不能提供真正好的随机数
这篇博文涵盖了许多用随机数获得更好随机数的方法
对于许多日常应用来说,这些可能是好的
但是,如果在多个线程上使用相同的随机数生成器,即使使用不同的种子,也会影响随机数的质量。这是因为您正在生成可能重叠的伪随机数序列
本视频更详细地解释了原因:
如果您想要真正的随机数,那么您确实需要使用crypto random number generator System.Security.Cryptography.RNGCryptoServiceProvider。这是线程安全的。一个核心问题:
不是线程安全的random.Next
- 使
随机。下一步
线程安全:解决质量问题,但不解决可伸缩性
- 使用多个PRNG:解决了可伸缩性问题,但可能会降低质量
var localRandom = new Random();
stopwatch.Reset();
stopwatch.Start();
var parallelSimulations = new List<int>();
Parallel.For(0, 20, run =>
{
var position = 0;
for (var step = 0; step < 10000000; step++)
{
if (localRandom.Next(0, 2) == 0)
{
position--;
}
else
{
position++;
}
}
Console.WriteLine(string.Format("Terminated run {0} at position {1}.", run, position));
parallelSimulations.Add(position);
});
Console.WriteLine(string.Format("Average position: {0} .", parallelSimulations.Average()));
stopwatch.Stop();
Console.WriteLine(string.Format("Time elapsed: {0}", stopwatch.ElapsedMilliseconds));
Console.ReadLine();
Parallel.For(0, 20, run =>
{
var localRandom = new Random();
var position = 0;