3

我习惯于跟随 xaml 创建一个简单的赛车应用程序

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

我使用以下代码

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

大多数时候(假设 90%)两个滑块似乎一起移动,而在调试中我可以看到每个线程为step. 怎么会?

4

3 回答 3

5

Random由时钟播种;您可能想要执行以下操作:

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

这将创建两个具有不同种子Random的单独实例(通过使用第一个来播种第二个),然后将它们传递给as 参数。这消除了由于时间而导致行为过度可预测的任何风险。Race

于 2013-11-14T09:59:25.657 回答
1

您应该在循环之外初始化随机生成器。

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

有关更多详细信息,请阅读 Jon Skeet 的这篇文章: https ://msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx

几乎每个包含“随机”和“重复”这两个词的 Stack Overflow 问题都有相同的基本答案。它是 .NET、Java 以及毫无疑问的其他平台中最常见的“陷阱”之一:在不指定种子的情况下创建新的随机数生成器将取决于当前时刻。与创建和使用随机数生成器的频率相比,计算机测量的当前时间不会经常变化 - 因此重复创建 Random 的新实例并使用它一次的代码最终会显示出很多重复.

于 2013-11-14T09:58:32.377 回答
1

当您创建一个新Random对象时,它会从系统时钟为其播种。这只有几毫秒的分辨率,所以如果你Random比这更频繁地创建一个新对象,它将产生与前一个相同的随机序列。

解决方案是只创建一个随机对象(lock如果有多个线程同时访问它,则使用 a 序列化访问它)。

于 2013-11-14T09:59:12.283 回答