Cha*_*ion 4 c# datetime timing stopwatch
我们有应用程序日志记录各种昂贵操作的性能信息.我们使用两者Stopwatch和DateTime.UtcNow我们的日志记录,我们发现这些值可能比预期的要大很多,即使给定DateTime.UtcNow的精度约为20ms.我的问题是什么可能导致这种情况并且可以修复?
记录的信息是:
DateTime.UtcNow)TimeSpan.FromSeconds((after - before) / (double)Stopwatch.Frequency),其中after和before是Stopwatch.GetTimestamp()操作开始和结束时的值DateTime.UtcNow)你会期望EndTime接近StartTime + Duration,但在某些情况下它会离开.我们对10000个这样的测量进行了采样,寻找EndTime和(StartTime + Duration)相差超过20ms的情况.我们发现了以下内容:
机器信息
这是可以预料的. 在引擎盖下StopWatch使用QueryPerformanceCounter(QPC),同时DateTime.UtcNow使用计算机的实时时钟(RTC).
为了测量经过的时间,你需要精度,因此应该使用Stopwatch.
要获得当前时间,您需要准确性,因此应该使用DateTime.UtcNow.
可以在MSDN上找到包含大量支持详细信息的精彩内容.
您测量的变化是由于RTC中的时钟漂移造成的.你的RTC(全部都是)会在实时提前或落后几毫秒.这很常见,并且通过NTP同步定期更正.对于微小的调整,操作系统将在几秒钟内以较小的间隔(几毫秒一次)展开校正.
就解决方法而言,你可以考虑这样一个类:
public static class PreciseClock
{
private static readonly DateTime StartTime = DateTime.UtcNow;
private static readonly Stopwatch Stopwatch = Stopwatch.StartNew();
public static DateTime GetCurrentUtcTime()
{
return StartTime + Stopwatch.Elapsed;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,缺点是您在初始化类时假设RTC处于完全同步状态.实际上,你无法保证这一点.
如果您需要某种程度的保证,可以考虑自己进行NTP调用.我已经在NodaTime.NetworkClock中实现了一个完全相同的类.它实现了Noda Time的IClock界面.它定期拨打NTP服务器,并使用a跟踪呼叫之间的时间.你会像这样使用它:Stopwatch
// grab the clock's singleton instance
var clock = NetworkClock.Instance;
// optionally set the ntp server during your app's startup
clock.NtpServer = "pool.ntp.org"; // or whatever server you want to sync with
// Get the current utc time whenever you like
DateTime utcNow = clock.Now.ToDateTimeUtc();
Run Code Online (Sandbox Code Playgroud)
此外,还有大多数现代硬件都可以使用的"多媒体计时器"或"高精度事件计时器"(HPET).它提供比QPC 更高的精度.但是,没有直接类在.NET Framework中公开它.如果你搜索,你会发现一些包含提供它的Win32函数的实现.通常情况下,除非您正在进行图形或音频之类的实时操作,否则这样做太过分了.