网上有很多讨论 Thread.Sleep()替代写法的文章,这里翻阅了《C#本质论》找了如下文字:
如何提高等待精度?
测试一:利用Thread.SpinWait + Stopwatch
Stopwatch 特点:
Operations timed using the system's high-resolution performance counter.
Timer frequency in ticks per second = 10000000
Timer is accurate within 100 nanoseconds
利用Stopwatch 纳秒级的计数精度+ 线程的自旋等待,消耗CPU时间
static void SpinWait(Stopwatch sw, int duration)
{
var current = sw.ElapsedMilliseconds;
while ((sw.ElapsedMilliseconds - current) < duration)
{
Thread.SpinWait(10);
}
}
测试代码:
static void Main(string[] args)
{
Console.WriteLine("======Test ...===========");
ThreadPool.QueueUserWorkItem((x) =>
{
int i = 0;
do
{
Stopwatch sw = new Stopwatch();
sw.Start();
SpinWait(sw, 500);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
i++;
} while (i < 30);
});
Console.ReadLine();
}
测试结果:
从测试结果看,等待时间计算非常精确;
写法二:参考来源他人blog
static void Main(string[] args)
{
Console.WriteLine("======Test ...===========");
Task.Delay(100).Wait();
ThreadPool.QueueUserWorkItem((x) =>
{
int i = 0;
do
{
Stopwatch sw = new Stopwatch();
sw.Start();
TimeDelay(500 * 1000);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
i++;
} while (i < 30);
});
public const int NULL = 0;
public const int QS_TIMER = 0x10;
public static void TimeDelay(int us)
{
long duetime = -10 * us;
int hWaitTimer = CreateWaitableTimer(NULL, true, NULL);
SetWaitableTimer(hWaitTimer, ref duetime, 0, NULL, NULL, false);
while (MsgWaitForMultipleObjects(1, ref hWaitTimer, false, Timeout.Infinite, QS_TIMER)) ;
CloseHandle(hWaitTimer);
}
[DllImport("kernel32.dll")]
public static extern int CreateWaitableTimer(int lpTimerAttributes, bool bManualReset, int lpTimerName);
[DllImport("kernel32.dll")]
public static extern bool SetWaitableTimer(int hTimer, ref long pDueTime,
int lPeriod, int pfnCompletionRoutine, // TimerCompleteDelegate
int lpArgToCompletionRoutine, bool fResume);
[DllImport("user32.dll")]
public static extern bool MsgWaitForMultipleObjects(uint nCount, ref int pHandles,
bool bWaitAll, int dwMilliseconds, uint dwWakeMask);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(int hObject);
测试结果:
精度也可以,对比测试1,有1个毫秒甚至更多15毫秒数的差别;
等待精度要求不太高的等待写法如下
public static void Sleep(int miniSeconds)
{
Task.Delay(miniSeconds).Wait();
}
或者如下面的代码:
Task.Run(async () => {
await Task.Delay(2000);
});
不管什么情况都要至少执行指定时间,超时也按指定时间内结束的写法如下:
public static void RunTimeOutTask(Action action, int miniSeconds)
{
Task.Factory.StartNew(() => {
action();
Task.Delay(miniSeconds).Wait();
}).Wait(miniSeconds);
}
实际测试有1-15个毫秒的偏差, 可能的原因应该是Task本身的超时等待Timer也是利用了操作系统计数器的频率,Windows 的系统定时器精度是 15.625ms,必须减少时间切片的长度,才有可能实现更高的精度。
Task.Delay的代码: http://www.voidcn.com/article/p-fzumrevc-bdp.html
参考:When to use Task.Delay, when to use Thread.Sleep?
高精度定时器实现:https://blog.gkarch.com/2015/09/high-resolution-timer.html#how-to-check-current-system-timer-resolution