如何使我的C#程序休眠50毫秒?
这似乎是一个简单的问题,但是我正处于暂时性的脑衰竭时刻!
1
| System.Threading.Thread.Sleep(50); |
但是请记住,在主GUI线程中执行此操作将阻止您的GUI更新(感觉"缓慢")。
只需删除;使其也适用于VB.net。
(几乎)任何编程语言都有3种选择可以等待:
宽松的等待
-
在给定的时间执行线程块(=不消耗处理能力)
-
无法在阻塞/等待的线程上进行处理
-
不太精确
紧等待(也称为紧循环)
-
处理器在整个等待时间间隔内非常繁忙(实际上,它通常消耗一个内核的处理时间的100%)
-
等待时可以执行一些动作
-
非常精确
前2个的组合
-
它通常结合了1.的处理效率和2的精度+做某事的能力。
1。-在C#中等待松散:
1
| Thread.Sleep(numberOfMilliseconds); |
但是,Windows线程调度程序导致Sleep()的准确性约为15ms(因此,即使计划仅等待1ms,睡眠也可以轻松地等待20ms)。
对于2-C#中的紧等待是:
1 2 3 4 5 6 7 8 9
| Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
//some other processing to do possible
if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
{
break;
}
} |
我们也可以使用DateTime.Now或其他时间测量方式,但是Stopwatch更快(并且这实际上在紧密循环中变得可见)。
3。-组合:
1 2 3 4 5 6 7 8 9 10
| Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
//some other processing to do STILL POSSIBLE
if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
{
break;
}
Thread.Sleep(1); //so processor can rest for a while
} |
该代码定期阻塞线程1毫秒(或稍长一些,具体取决于OS线程调度),因此处理器在阻塞时间并不忙,并且代码不会消耗100%的处理器功率。在阻塞之间仍然可以执行其他处理(例如:UI更新,事件处理或进行交互/通信工作)。
您无法在Windows中指定确切的睡眠时间。为此,您需要一个实时操作系统。您能做的最好的就是指定最短的睡眠时间。然后由调度程序在那之后唤醒您的线程。永远不要在GUI线程上调用.Sleep()。
从现在开始,您具有异步/等待功能,最好的睡眠时间为50ms是使用Task.Delay:
1 2 3 4 5
| async void foo()
{
// something
await Task.Delay(50);
} |
或者,如果您以.NET 4(针对VS2010的Async CTP 3或Microsoft.Bcl.Async)为目标,则必须使用:
1 2 3 4 5
| async void foo()
{
// something
await TaskEx.Delay(50);
} |
这样,您就不会阻塞UI线程。
使用此代码
1 2 3
| using System.Threading;
// ...
Thread.Sleep(50); |
线程将不会在指定的时间内调度为由操作系统执行。此方法将线程的状态更改为包括WaitSleepJoin。
此方法不执行标准COM和SendMessage泵送。
如果您需要在具有STAThreadAttribute的线程上睡眠,但是要执行标准的COM和SendMessage泵送,请考虑使用Join方法的重载之一,该重载指定超时间隔。
为了提高可读性:
1 2
| using System.Threading;
Thread.Sleep(TimeSpan.FromMilliseconds(50)); |
从.NET Framework 4.5开始,可以使用:
1 2 3
| using System.Threading.Tasks;
Task.Delay(50).Wait(); // wait 50ms |
两全其美:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| using System.Runtime.InteropServices;
[DllImport("winmm.dll", EntryPoint ="timeBeginPeriod", SetLastError = true)]
private static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint ="timeEndPeriod", SetLastError = true)]
private static extern uint TimeEndPeriod(uint uMilliseconds);
/**
* Extremely accurate sleep is needed here to maintain performance so system resolution time is increased
*/
private void accurateSleep(int milliseconds)
{
//Increase timer resolution from 20 miliseconds to 1 milisecond
TimeBeginPeriod(1);
Stopwatch stopwatch = new Stopwatch();//Makes use of QueryPerformanceCounter WIN32 API
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds < milliseconds)
{
//So we don't burn cpu cycles
if ((milliseconds - stopwatch.ElapsedMilliseconds) > 20)
{
Thread.Sleep(5);
}
else
{
Thread.Sleep(1);
}
}
stopwatch.Stop();
//Set it back to normal.
TimeEndPeriod(1);
} |