Mat*_*ias 8 random simulation parallel-processing task-parallel-library
我刚开始玩任务并行库,遇到了有趣的问题; 我对将要发生的事情有一个大概的了解,但是希望听到比我更有能力的人的评论来帮助了解正在发生的事情.我为有点冗长的代码道歉.
我开始使用随机游走的非并行模拟:
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();
Run Code Online (Sandbox Code Playgroud)
然后我在并行循环中写了我的第一次尝试:
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();
Run Code Online (Sandbox Code Playgroud)
当我在设置为仅使用1个核心的虚拟机上运行它时,我观察到相似的持续时间,但运行不再按顺序处理 - 毫不奇怪.
当我在双核机器上运行时,事情变得奇怪了.我没有看到任何时间的改进,并且每次运行都观察到一些非常奇怪的结果.大多数运行最终结果为-1,000,000(或非常接近),这表明Random.Next一直返回0准.
当我为每个循环制作随机局部时,一切正常,我得到了预期的持续时间改进:
Parallel.For(0, 20, run =>
{
var localRandom = new Random();
var position = 0;
Run Code Online (Sandbox Code Playgroud)
我的猜测是问题与Random对象在循环之间共享并且具有某种状态这一事实有关."失败的并行"版本的持续时间缺乏改善是我假设由于没有并行处理对Random的调用(即使我看到并行版本使用两个核心,而原始版本没有) .我真正没有得到的部分是为什么模拟结果是它们的原因.
我有一个单独的担心是,如果我在每个循环中使用局部的Random实例,我可能会遇到以相同的种子开始的多个循环的问题(当你生成多个Random的时间过于接近时产生的问题,导致相同的序列).
任何有关正在发生的事情的见解对我来说都是非常有价值的!
这些方法都不会给你真正好的随机数。
这篇博文涵盖了许多使用 Random 获得更好随机数的方法
这些可能适合许多日常应用。
但是,如果您在多个线程上使用相同的随机数生成器,即使使用不同的种子,您仍然会影响随机数的质量。这是因为您正在生成可能重叠的伪随机数序列。
该视频更详细地解释了原因:
http://software.intel.com/en-us/videos/tim-mattson-use-and-abuse-of-random-numbers/
如果您想要真正的随机数,那么您确实需要使用加密随机数生成器 System.Security.Cryptography.RNGCryptoServiceProvider。这是线程安全的。