奇怪的是,您的代码在我的 Win7 下的四核上运行得非常好,几乎每次都产生恰好相隔 2 毫秒的值。
所以我做了一个更彻底的测试。这是我的示例输出Thread.Sleep(1)
。DateTime.UtcNow
该代码在循环中打印连续调用之间的毫秒数:
每行包含 100 个字符,因此代表“干净运行”的 100 毫秒时间。所以这个屏幕大约覆盖了 2 秒。最长抢占4ms;此外,有一段时间持续大约 1 秒,而每次迭代恰好需要 1 毫秒。这几乎是实时的操作系统质量!1 :)
所以我又试了一次,Thread.Sleep(2)
这次:
再次,几乎完美的结果。这次每行有 200 毫秒长,并且有一个运行将近 3 秒的时间,其中的间隔只有 2 毫秒。
自然,接下来要看的是DateTime.UtcNow
我机器上的实际分辨率。这是一次完全不睡觉的跑步;.
如果UtcNow
根本没有更改,则打印a :
最后,在产生上述结果的同一台机器上调查时间戳相差 15 毫秒的奇怪案例时,我遇到了以下奇怪的事件:
Windows API 中有一个叫做 的函数timeBeginPeriod
,应用程序可以使用它来临时增加定时器频率,所以这大概就是这里发生的事情。计时器分辨率的详细文档可通过Hardware Dev Center Archive获得,特别是Timer-Resolution.docx(一个 Word 文件)。
结论:
DateTime.UtcNow
可以有比 15ms 高得多的分辨率
Thread.Sleep(1)
可以睡正好 1ms
- 在我的机器上,
UtcNow
一次增长正好 1 毫秒(给出或取舍入误差 - 反射器显示 中有一个除法UtcNow
)。
- 当一切都基于 15.6 毫秒时,该过程可以切换到低分辨率模式,以及动态切换到具有 1 毫秒切片的高分辨率模式。
这是代码:
static void Main(string[] args)
{
Console.BufferWidth = Console.WindowWidth = 100;
Console.WindowHeight = 20;
long lastticks = 0;
while (true)
{
long diff = DateTime.UtcNow.Ticks - lastticks;
if (diff == 0)
Console.Write(".");
else
switch (diff)
{
case 10000: case 10001: case 10002: Console.ForegroundColor=ConsoleColor.Red; Console.Write("1"); break;
case 20000: case 20001: case 20002: Console.ForegroundColor=ConsoleColor.Green; Console.Write("2"); break;
case 30000: case 30001: case 30002: Console.ForegroundColor=ConsoleColor.Yellow; Console.Write("3"); break;
default: Console.Write("[{0:0.###}]", diff / 10000.0); break;
}
Console.ForegroundColor = ConsoleColor.Gray;
lastticks += diff;
}
}
事实证明,存在一个可以改变计时器分辨率的未记录函数。我没有调查细节,但我想我会在这里发布一个链接:NtSetTimerResolution
.
1当然,我特别确定操作系统尽可能空闲,并且有四个相当强大的 CPU 内核可供使用。如果我将所有四个内核都加载到 100%,那么情况就会完全改变,到处都是长时间的抢占。