我有一个循环运行的代码,它根据当前时间保存状态.有时这可能只相差几毫秒,但由于某些原因,似乎DateTime.Now将始终返回至少10 ms的值,即使它仅在2或3 ms之后.这是一个主要问题,因为我保存的状态取决于它保存的时间(例如录制内容)
我的测试代码返回10 ms的每个值:
public static void Main()
{
var dt1 = DateTime.Now;
System.Threading.Thread.Sleep(2);
var dt2 = DateTime.Now;
// On my machine the values will be at least 10 ms apart
Console.WriteLine("First: {0}, Second: {1}", dt1.Millisecond, dt2.Millisecond);
}
Run Code Online (Sandbox Code Playgroud)
是否有另一种解决方案可以获得精确的当前时间到毫秒?
有人建议看秒表类.虽然秒表类是非常准确的,但它并没有告诉我当前的时间,我需要的东西是为了保存程序的状态.
Rom*_*kov 41
奇怪的是,你的代码在我的Win7下的四核上运行得非常好,几乎每次都产生相距2毫秒的值.
所以我做了一个更全面的测试.这是我的示例输出Thread.Sleep(1).代码打印DateTime.UtcNow循环中连续调用之间的ms数:

每行包含100个字符,因此在"干净运行"中表示100毫秒的时间.所以这个屏幕大约需要2秒钟.最长的抢占时间是4毫秒; 此外,当每次迭代花费1毫秒时,有一个持续约1秒的周期.这几乎是实时操作系统的质量!1 :)
所以我再次尝试,Thread.Sleep(2)这次:

再次,几乎完美的结果.这一次每行的长度为200ms,并且运行时间差不多为3秒,其中间隙从未超过2ms.
当然,接下来要看的是DateTime.UtcNow我机器上的实际分辨率.这是一场完全没有睡觉的跑步; 一个.印,如果UtcNow不改变在所有:

最后,在调查一个奇怪的时间戳相差15ms的情况下,在产生上述结果的同一台机器上,我遇到了以下奇怪的事件:

Windows API中有一个函数被调用timeBeginPeriod,哪些应用程序可以用来暂时增加定时器频率,所以这可能就是这里发生的事情.定时器分辨率的详细文档可通过硬件开发中心存档获得,特别是Timer-Resolution.docx(一个Word文件).
结论:
DateTime.UtcNow 可以有比15ms更高的分辨率Thread.Sleep(1) 可以睡1msUtcNow增长一次只增加1ms(给出或采取舍入错误 - 反射器显示有一个分区UtcNow).这是代码:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
事实证明,存在一个可以改变计时器分辨率的无证功能.我没有调查过细节,但我想我会在这里发布一个链接:NtSetTimerResolution.
1 当然,我更加确定操作系统尽可能空闲,并且有四个相当强大的CPU核心可供使用.如果我将所有四个核心加载到100%,则图像会完全改变,并且在任何地方都会有长时间的抢占.
Chr*_*ris 10
处理毫秒时DateTime的问题不是由于DateTime类,而是与CPU标记和线程切片有关.本质上,当调度程序暂停操作以允许其他线程执行时,它必须在恢复之前至少等待1个时间片,这在现代Windows操作系统上大约需要15ms.因此,任何暂停低于15ms精度的尝试都会导致意外结果.
Roh*_*est -4
您可以使用 DateTime.Now.Ticks,阅读MSDN上的文章
“一个刻度代表一百纳秒或百万分之一秒。”