0%

C#高精度定时器

结论: 推荐调用timeBeginPeriod后使用Sleep(1)精度在2ms以内

DateTime.Now

该属性发解析取决于系统计时器, 后者取决于基础操作系统, 精度一般介于0.5~15ms之间
该属性通常用于度量性能, 由于分辨路较低不适合用于测试工具, 推荐使用Stopwatch类

Stopwatch

Stopwatch内部使用系统API QueryPerformanceCounter / QueryPerformanceFrequency来进行高精度计时,
精度依赖于硬件通常高达几十纳秒(ns)

测试一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Stopwatch sw = new Stopwatch();
sw.Start();
Thread.Sleep(1);
sw.Stop();
TimeSpan timeSpan = sw.Elapsed;

double ms = timeSpan.TotalMilliseconds;

//实际定时时间大约15.6ms
/*
该测试取决于系统时钟, Windows默认时钟频率为每秒64次即15.625ms
小于16ms的Sleep不会生效
可以调用timeBeginPeriod更改时钟频率
*/

测试二

1
2
3
4
5
6
7
8
9
10
11
12
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
public static extern uint BeginPeriod(uint ms);
BeginPeriod(1);
Stopwatch sw = new Stopwatch();
sw.Start();
Thread.Sleep(1);
sw.Stop();
TimeSpan timeSpan = sw.Elapsed;

double ms = timeSpan.TotalMilliseconds;

//实际定时时间大约1.8ms

测试三

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
[DllImport("kernel32.dll")]
public static extern short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
public static extern short QueryPerformanceFrequency(ref long x);

public void delay(long delayTime)
{
long stopValue = 0, startValue = 0, freq = 0, n = 0;
QueryPerformanceFrequency(ref freq);
long count = delayTime * freq / 1000000;//1000us = 1ms
QueryPerformanceCounter(ref startValue);
while(n < count)
{
QueryPerformanceCounter(ref stopValue);
n = stopValue - startValue;
}
}
Stopwatch sw = new Stopwatch();
sw.Start();
delay(1000);
sw.Stop();
TimeSpan timeSpan = sw.Elapsed;

double ms = timeSpan.TotalMilliseconds;
//实际定时时间大约1.3ms