C# Thread.Sleep(1000) takes much more than 1000ms

2019-03-03 12:53发布

问题:

I write a c# program to count down 5 seconds. What I do is:

        new Task(() =>
        {

                try
                {
                        this.Invoke((Action)delegate()
                        {
                            label1.Text = "5"; // 4, 3, 2..etc
                        });
                    }
                    Thread.Sleep(1000);
                }
                catch
                {
                    // form could be disposed
                    break;
                }

            }

        }).Start();

This works on my PC, however, when I copied the program to a window tablet, the Thread.Sleep(1000) gives more than 1 second. In other words, it takes more than 5 seconds (in fact more than 10 seconds) to update the label from 5,4,3,2,1. Alternatively, it takes too long to update label1.Text = "5", etc? It does not make sense to me. I wonder what is wrong?

回答1:

Sleep will wait at least that long before activating the thread again, but it can always be longer than that. After the one second time has passed the thread becomes eligible to execute by the CPU scheduler, and the scheduler is able to run it whenever it wants to. If it's particularly busy, and/or is using a scheduling algorithm that doesn't focus on quickly allowing newly active threads to run, it could be some time.



回答2:

Servy's answer is correct. For more details, please read the documentation:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298.aspx

which states:

Note that a ready thread is not guaranteed to run immediately. Consequently, the thread may not run until some time after the sleep interval elapses. For more information, see Scheduling Priorities.

The priority documentation is here:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms685100.aspx

More generally though: you are doing something deeply wrong. Do not ever use Sleep like this. If you want to wait some amount of time then use a timer or use a Delay task. Never sleep a thread like this outside of test code. The right way to write your code is probably something like

for (int countdown = 5; countdown > 0; countdown -= 1)
{
    label1.Text = countdown.ToString();
    await Task.Delay(1000);
}

Or, make a class that has a timer and a counter, start the timer to tick a few times a second, compare the current time to the time when you last updated the label, and if more than a second has elapsed, update the label.