DateTime.Now更新频率如何? 或者是否有更精确的API来获取

我的代码运行在一个循环中,并且基于当前时间保存状态。 有时候这可能只是几毫秒,但由于某些原因,即使仅仅2或3毫秒后,DateTime.Now总会返回至少10毫秒的值。 这是一个主要问题,因为我保存的状态取决于保存的时间(例如记录某些内容)

我的测试代码每10毫秒返回一个值:

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);
}

如何获得准确的当前时间达到毫秒还有另一种解决方案吗?

有人建议看看秒表班。 尽管秒表类非常准确,但它并不告诉我当前时间,这是我需要的,以便保存我的程序状态。


奇怪的是,你的代码在我的Win7下的四核上工作得非常好,几乎每次都会产生相距2毫秒的值。

所以我做了一个更彻底的测试。 这是我的Thread.Sleep(1)示例输出。 该代码打印循环中对DateTime.UtcNow连续调用之间的毫秒数:

睡1

每行包含100个字符,因此在“全面运行”中表示100毫秒的时间。 所以这个屏幕大约需要2秒。 最长抢占为4ms; 此外,当每次迭代精确到1毫秒时,持续约1秒。 这几乎是实时的操作系统质量!1 :)

所以我这次再次尝试Thread.Sleep(2)

睡2

再次,几乎完美的结果。 这一次每一行都是200ms长,并且有一个长达3秒的跑步,其间的差距永远不会超过2毫秒。

自然,接下来要看到的是我的机器上的DateTime.UtcNow的实际分辨率。 这是一场没有睡觉的跑步; a . 如果UtcNow完全没有改变,则打印出来:

没有睡眠

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

在这里输入图像描述在这里输入图像描述

在Windows API中有一个名为timeBeginPeriod的函数,应用程序可以使用该函数临时增加计时器频率,所以这可能是这里发生的事情。 定时器分辨率的详细文档可通过硬件开发中心档案,特别是Timer-Resolution.docx(一个Word文件)获得。

结论:

  • DateTime.UtcNow 可以具有比15ms高得多的分辨率
  • Thread.Sleep(1) 可以睡1ms
  • 在我的机器上, UtcNow增长1毫秒(给出或取舍舍错误 - 反射器显示UtcNow中存在分裂)。
  • 这个过程有可能在一切都是基于15.6ms的时候切换到低分辨率模式,在运行时切换到高分辨率模式,1ms切片。
  • 代码如下:

    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%,则图片完全变化,并且随处都有抢先占用。


    DateTime在处理毫秒时的问题根本不是由于DateTime类造成的,而是与CPU ticks和线程片有关。 本质上,当调度程序暂停某个操作以允许其他线程执行时,它必须至少等待一个时间片,然后才能在现代Windows操作系统上恢复大约15ms。 因此,任何暂停时间小于15ms精度的尝试都会导致意想不到的结果。


    如果您在做任何事情之前拍摄当前时间的快照,您可以将秒表添加到您存储的时间,不是?

    链接地址: http://www.djcxy.com/p/52807.html

    上一篇: How frequent is DateTime.Now updated ? or is there a more precise API to get the current time?

    下一篇: Control the start, stop and restart of tasks