I'm using to following xaml to create a simple racer app

<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. How come?

有帮助吗?

解决方案

Random is seeded by the clock; 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. 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

Almost every Stack Overflow question which includes the words "random" and "repeated" has the same basic answer. 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. 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.

When you create a new Random object, it seeds it from the system clock. 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.

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).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top