简体   繁体   English

在多个线程中使用Random共享相同的方法

[英]Using Random in multiple threads sharing same method

I'm using to following xaml to create a simple racer app 我正在使用跟随xaml创建一个简单的赛车应用程序

<StackPanel>
    <Slider x:Name="racerOne" Maximum="1000"/>
    <Slider x:Name="racerTwo" Maximum="1000"/>
    <Button Content="Start Race" Click="myButton_Click"/>
</StackPanel>

I use the following code 我使用以下代码

    private void myButton_Click(object sender, RoutedEventArgs e)
    {
        Task firstRacer = Task.Run(() => Race(racerOne));
        Task secondRacer = Task.Run(() => Race(racerTwo));
    }

    private void Race(Slider racer)
    { 
        int step = 0;

        while (step < 1000)
        {
            step += new Random().Next(0, 10);
            Dispatcher.BeginInvoke(new ThreadStart(() => racer.Value = step));
            Thread.Sleep(new Random().Next(0, 300));
        }
    }

Most of the times (let's say 90% precent) both sliders appear to move together, while in debug I can see each thread generates different values for step . 大多数时候(比如90%的前提)两个滑块似乎一起移动,而在调试中我可以看到每个线程为step生成不同的值。 How come? 怎么会?

Random is seeded by the clock; Random是由时钟播种的; you might want to do something like: 你可能想做类似的事情:

Random rand1 = new Random();
Random rand2 = new Random(rand1.Next());
Task firstRacer = Task.Run(() => Race(racerOne, rand1));
Task secondRacer = Task.Run(() => Race(racerTwo, rand2));

private void Race(Slider racer, Random rand)
{ 
    int step = 0;

    while (step < 1000)
    {
        step += rand.Next(0, 10);
        Dispatcher.BeginInvoke(new ThreadStart(() => racer.Value = step));
        Thread.Sleep(rand.Next(0, 300));
    }
}

This creates two separate Random instances with different seeds (by using the 1st to seed the second), and then passes these into the Race as arguments. 这将创建两个具有不同种子的单独Random实例(通过使用1st来播种第二个),然后将这些实例作为参数传递给Race This removes any risk of overly-predictable behaviour due to timing. 这消除了由于时间而导致过度可预测行为的风险。

You should initialize your random generator outside of the loop. 您应该在循环之外初始化随机生成器。

var rand = new Random();
while (step < 1000)
        {
            step += rand.Next(0, 10);
            Dispatcher.BeginInvoke(new ThreadStart(() => racer.Value = step));
            Thread.Sleep(rand.Next(0, 300));
        }

For more details please go through this Jon Skeet's article: https://msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx 有关详细信息,请参阅Jon Skeet的文章: https//msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx

Almost every Stack Overflow question which includes the words "random" and "repeated" has the same basic answer. 几乎每个包含“随机”和“重复”字样的Stack Overflow问题都有相同的基本答案。 It's one of the most common "gotchas" in .NET, Java, and no doubt other platforms: creating a new random number generator without specifying a seed will depend on the current instant of time. 它是.NET,Java中最常见的“陷阱”之一,毫无疑问是其他平台:创建一个新的随机数生成器而不指定种子将取决于当前的时刻。 The current time as measured by the computer doesn't change very often compared with how often you can create and use a random number generator – so code which repeatedly creates a new instance of Random and uses it once will end up showing a lot of repetition. 与您创建和使用随机数生成器的频率相比,计算机测量的当前时间不会经常变化 - 因此重复创建Random的新实例并使用它一次的代码最终将显示出大量重复。

When you create a new Random object, it seeds it from the system clock. 当您创建一个新的Random对象时,它会从系统时钟中播种它。 This has a resolution of only a few milliseconds, so if you create a new Random object more frequently than that, it will produce the same random sequence as the previous one. 它的分辨率只有几毫秒,因此如果您创建一个比这更频繁的新Random对象,它将产生与前一个相同的随机序列。

The solution is to create only ONE random object (and use a lock to serialise access to it if more than one thread is accessing it at once). 解决方案是只创建一个随机对象(如果多个线程一次访问它,则使用lock序序对其进行访问)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM