【问题标题】:Does Stopwatch.Gettimestamp ever roll over? Or roll back?Stopwatch.Gettimestamp 是否会翻转?还是回滚?
【发布时间】:2012-02-17 08:13:36
【问题描述】:

在使用 Stopwatch.GetTimestamp() 时,我们发现如果你记录返回值,然后继续调用它并与之前的返回值进行比较,它最终会但不可预测地返回一个小于原始值的值。

这是预期的行为吗?

在生产代码中这样做的目的是为了获得精确到微秒的系统时间。

该技术涉及调用 DateTime.UtcNow 并分别调用 Stopwatch.GetTimestamp() 作为 originalUtcNow 和 originalTimestamp。

从那时起,应用程序只需调用 Stopwatch.GetTimestamp() 并使用 Stopwatch.Frequency 计算与 originalTimestamp 变量的差值,然后将该差值添加到 originalUtcNow。

那么,瞧……一个高效且准确的微秒 DateTime。

但是,我们发现有时 Stopwatch.GetTimestamp() 会返回较小的数字。

这种情况很少发生。我们的想法是在发生这种情况时简单地“重置”并继续。

但是,这让我们怀疑 Stopwatch.GetTimestamp() 的准确性或怀疑 .Net 库中存在错误。

如果您能对此有所了解,请这样做。

仅供参考,根据当前时间戳值、频率和 long.MaxValue,除非是硬件问题,否则它似乎不太可能在我们的生命周期内翻转。

编辑:我们现在“每个线程”计算这个值,然后“钳制它”以观察核心之间的跳转以重置它。

【问题讨论】:

  • UtcNow 不是微秒精度时,你怎么能有一个“微秒精度的系统时间”?这个数字只能用于精确的时间间隔。
  • 对不起。你看我的解释了吗?它只在应用程序启动时调用一次 UtcNow。从那时起,它使用系统时钟并计算差异以获得当前时间。
  • 秒表在可以访问或存在于计算机上时使用高分辨率计时器。
  • Acquiring high-resolution time stamps 有关于高性能计数器时间戳的详细说明,并附有插图和常见问题解答。

标签: c# .net timestamp rollover stopwatch


【解决方案1】:

您可能会及时获得跳跃,因为您的线程正在跳跃核心。见本页“注”:http://msdn.microsoft.com/en-us/library/ebf7z0sw.aspx

【讨论】:

  • 谢谢!这符合逻辑,因为它是一个多线程应用程序。您的链接确认硬件和 BIOS 问题可能导致此问题。我相信你的答案。关于如何解决这个问题的任何建议?我们只是保持“lastClockTime”并进行比较,它比我们重置的要少。
  • @Wayne:Environment.TickCount 显然没有遇到这个问题,但是它不太精确,不到一个月就溢出了。
  • 我们已经遭受了溢出。这很痛苦。而且它对于我们的需求来说太不精确了。无论如何,感谢您提供。
  • @Groo 1) 你确定吗? 2)精度是多少?是1ms吗?还是 15.6 毫秒? (除非你增加计时器分辨率)
  • @Eugen:不,我对此发表评论是错误的。 Environment.TickCount 的分辨率约为 16 毫秒,因此获得更好分辨率的唯一方法是使用 QueryPerformanceCounter(或在后台使用此功能的 Stopwatch,前提是该系统上有高分辨率计数器) .
【解决方案2】:

Stopwatch 类的行为会因系统而异,具体取决于硬件支持。

见:http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.ishighresolution.aspx

另外,我相信底层等效的 win32 调用 (QueryPerformanceCounter) 包含有用的文档:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx

【讨论】:

    【解决方案3】:

    我不知道关于向后跑的确切信息(这听起来像一个小的向后变化),但到目前为止我已经经历了三倍,Stopwatch.GetTimestamp() 的值可以改变所以非常重要的是,它会在一些进一步的形式计算中导致 溢出异常,如下所示:
    (Stopwatch.GetTimestamp() - ProgramStartStopwatchTimestamp) * n
    其中 n 是一个很大的值,但足够小,如果秒表没有大幅跳动,那么程序可以运行数年而不会出现溢出异常。另请注意,这些异常发生在程序启动数小时后,因此问题不仅仅是秒表在启动后立即向后运行。它只是跳到了完全不同的范围,无论朝哪个方向。

    关于秒表翻转,在上述一种情况下,它(不是差异,而是秒表)获得了 0xFF4 的值? ??? ??? ????,所以它跳到了一个非常接近翻滚的范围。多次重新启动程序后,这个新范围仍然有效。如果考虑到无论如何都需要处理跳跃,这很重要......

    如果还需要确定时间戳是在哪个内核上进行的,那么了解正在执行的内核编号可能会有所帮助。为此,有称为GetCurrentProcessorNumber(自Server 2003 和Vista 起可用)和GetCurrentProcessorNumberEx(自Server 2008 R2 和Windows 7 起可用)的函数。另请参阅this question's answers 了解更多选项(包括 Windows XP)。
    请注意,调度程序可以随时更改核心编号。但是如果在读取秒表时间戳之前和之后读取核心编号,并且核心编号保持不变,那么也许可以假设秒表读取也在这个核心上执行......

    【讨论】:

      【解决方案4】:

      要具体回答高级问题“Stopwatch.GetTimestamp() 多久翻转一次?”,Microsoft's answer 是:

      自最近一次系统启动起不少于 100 年,并且根据使用的底层硬件计时器可能更长。对于大多数应用程序,翻转不是问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-21
        • 1970-01-01
        • 1970-01-01
        • 2011-03-07
        • 2020-04-01
        • 2020-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多