并行循环和随机产生奇怪的结果 [英] Parallel loops and Random produce odd results

查看:77
本文介绍了并行循环和随机产生奇怪的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始使用Task Parallel Library,并遇到了有趣的问题;我对正在发生的事情有一个大致的了解,但是我想听听比我更有能力的人的评论,以帮助您了解正在发生的事情.对于较长的代码,我深表歉意.

I just started playing with the Task Parallel Library, and ran into interesting issues; I have a general idea of what is going on, but would like to hear comments from people more competent than me to help understand what is happening. My apologies for the somewhat lengthy code.

我从随机游走的非并行模拟开始:

I started with a non-parallel simulation of a random walk:

 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();

然后我在并行循环中进行了第一次尝试:

I then wrote my first attempt at a parallel loop:

 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();

当我在设置为仅使用1个内核的虚拟机上运行它时,我观察到了类似的持续时间,但是不再按顺序处理运行-不足为奇.

When I ran it on a virtual machine set to use 1 core only, I observed a similar duration, but the runs are no longer processed in order - no surprise.

当我在双核计算机上运行它时,事情变得很奇怪.我没有看到时间上的改善,并且每次运行都观察到一些非常奇怪的结果.大多数运行的结果为-1,000,000(或非常接近),这表明Random.Next始终返回0准.

When I ran it on a dual-core machine, things went odd. I saw no improvement in time, and observed some very weird results for each run. Most runs end up with results of -1,000,000, (or very close), which indicates that Random.Next is returning 0 quasi all the time.

当我在每个循环中设置随机局部时,一切工作都很好,并且我得到了预期的持续时间改进:

When I make the random local to each loop, everything works just fine, and I get the expected duration improvement:

Parallel.For(0, 20, run =>
         {
            var localRandom = new Random();
            var position = 0; 

我的猜测是,问题与以下事实有关:Random对象在循环之间共享,并且具有某种状态.我认为在失败的并行"版本中持续时间没有改善,是由于以下事实:对Random的调用不会并行处理(即使我看到并行版本同时使用了两个内核,而原始版本则没有) .我真正不明白的是为什么仿真结果才是真实的.

My guess is that the problem has to do with the fact that the Random object is shared between the loops, and has some state. The lack of improvement in duration in the "failing parallel" version is I assume due to that fact that the calls to Random are not processed in parallel (even though I see that the parallel version uses both cores, whereas the original doesn't). The piece I really don't get is why the simulation results are what they are.

我要担心的另一个问题是,如果我在每个循环中使用本地的Random实例,则可能会遇到从同一种子开始的多个循环的问题(当您生成多个Randoms的时间太近时会遇到的问题,产生相同的序列).

One separate worry I have is that if I use Random instances local to each loop, I may run into the problem of having multiple loops starting with the same seed (the issue you get when you generate multiple Randoms too close in time, resulting in identical sequences).

任何对正在发生的事情的见解对我来说都是非常有价值的!

Any insight in what is going on would be very valuable to me!

推荐答案

这两种方法都不能为您提供非常好的随机数.

Neither of these approaches will give you really good random numbers.

这篇博客文章介绍了许多使用Random获得更好随机数的方法

This blog post covers a lot of approaches for getting better random numbers with Random

http://blogs.msdn.com /b/pfxteam/archive/2009/02/19/9434171.aspx

对于许多日常应用来说,这些可能很好.

These may be fine for many day to day applications.

但是,如果在多个线程上使用相同的随机数生成器,甚至具有不同的种子,则仍然会影响随机数的质量.这是因为您正在生成可能重叠的伪随机数序列.

However if you use the same random number generator on multiple threads even with different seeds you will still impact the quality of your random numbers. This is because you are generating sequences of pseudo-random numbers which may overlap.

此视频详细解释了原因:

This video explains why in a bit more detail:

http: //software.intel.com/zh-CN/videos/tim-mattson-use-and-abuse-of-random-numbers/

如果您真的想要随机数,那么您确实需要使用加密随机数生成器System.Security.Cryptography.RNGCryptoServiceProvider.这是线程安全的.

If you want really random numbers then you really need to use the crypto random number generator System.Security.Cryptography.RNGCryptoServiceProvider. This is threadsafe.

这篇关于并行循环和随机产生奇怪的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆