为什么选择DateTime.现在和StopWatch漂移

本文关键字:StopWatch 漂移 选择 DateTime 为什么 | 更新日期: 2023-09-27 18:00:53

我在C#中制作了一个小型测试应用程序,用于设置DateTime.Now并启动StopWatch。每十秒钟打印一次_stopwatch.Elapsed.TotalMilliseconds(DateTime.Now - _startTime).TotalMilliseconds

虽然我不认为两者完全相同,但我很惊讶地看到它们以每20秒1毫秒的速度线性发散。我假设DateTime.Now调用系统时钟,而StopWatch进行某种累加?

样本输出:

StopWatch : 0,2  DateTime : 1,0 Diff : 0,81
StopWatch : 10000,5  DateTime : 10002,6 Diff : 2,04
(...)
StopWatch : 2231807,5  DateTime : 2231947,7 Diff : 140,13
StopWatch : 2241809,5  DateTime : 2241950,2 Diff : 140,70

完整来源:https://gist.github.com/knatten/86529563122a342de6bb

输出:https://gist.github.com/knatten/84f9be9019ee63119ee2

为什么选择DateTime.现在和StopWatch漂移

答案相对直截了当。

  • Stopwatch使用性能计数器来计算处理器的滴答声,这种机制在处理器之间有所不同
  • DateTime查询系统时钟-系统时钟由windows使用主板上的(可能是石英(晶体时钟的输出定期更新

所有时钟都会漂移,这两种不同的定时机制将以不同的速率漂移。

在引擎盖下,Stopwatch使用这种API

Stopwatch类有助于操纵与计时相关的托管代码中的性能计数器。具体而言,频率字段和GetTimestamp方法可以代替非托管Win32 API QueryPerformanceFrequency和QueryPerformanceCounter。

DateTime使用此API

DateTime.Now每隔几毫秒一次。此外,它的滴答声在不同的机器之间也不是固定的。在现代windows系统的机器上,你可以预期刻度分辨率将在每秒100个刻度左右。

另一方面,StopWatch查询CPU硬件以获得较高的精度。实际上,使用Stopwatch.Frequency可以得到StopWatch的分辨率。

我不知道以上两个,直到我读到埃里克·利珀特的一篇有趣的帖子,关于常见的性能基准错误,请看这里。这真是一个很棒的帖子。

StopwatchDateTime精确得多,这将解释的差异

来自MSDN:

Stopwatch通过计算底层计时器机制中的计时器刻度来测量运行时间。如果安装的硬件和操作系统支持高分辨率性能计数器,则Stopwatch类会使用该计数器来测量运行时间。否则,Stopwatch类使用系统计时器来测量经过的时间。使用Frequency和IsHighResolution字段来确定秒表计时实现的精度和分辨率。