经过时间测量错误

时间:2014-07-16 23:19:06

标签: c# datetime stopwatch

在经过时间测量过程中偶然发现意外行为。

我从Stopwatch班开始:

for (int i = 0; i < 100; i++)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    Thread.Sleep(200);
    stopwatch.Stop();
    Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

https://dotnetfiddle.net/3hch1R

但事实证明,每过一段时间就会少于200毫秒。

然后是DateTime.Now的时间,它也显示出一些奇怪的东西:

for (int i = 0; i < 100; i++)
{
    var start = DateTime.Now.Millisecond;
    Thread.Sleep(200);
    var stop = DateTime.Now.Millisecond;
    Console.WriteLine(stop - start);    
}

https://dotnetfiddle.net/2vo2yw

这很简单,因为这会定期返回负面结果。

所以我的问题是:这两种课程的行为是什么原因以及如何更准确地测量经过时间(没有负偏差)?
有一个关于这个主题的post秒表,但是那里的评论看起来有些矛盾。

EDIT1:
正如AlexD发现的那样,DateTime.Now.Millisecond只返回一个毫秒部分,而不是TotalMilliseconds。所以这个很清楚。

EDIT2:
根据建议,我决定使用DateTime,它的结果满足我的精度要求:

for (int i = 0; i < 100; i++)
{
    var start = (int)DateTime.UtcNow.TimeOfDay.TotalMilliseconds;
    Thread.Sleep(200);
    var stop = (int)DateTime.UtcNow.TimeOfDay.TotalMilliseconds;
    Console.WriteLine(stop - start);    
}

DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond如果测量之间的日期变化是您的情况。

2 个答案:

答案 0 :(得分:2)

广告1:Thread.Sleep不是一个非常准确的睡眠方法...我建议你使用睡眠和忙碌等待的组合:睡眠,比如180ms,然后使用忙等待直到你达到200ms;这将在最后20ms内加载CPU 100%(平均CPU负载为10%,这可能是合理的),但会给你更准确的发布时间。

广告2:使用DateTime.Ticks(http://msdn.microsoft.com/en-us/library/system.datetime.ticks(v=vs.110).aspx),它返回&#39;刻度线的数量&#39; (时间间隔为100秒)从时间开始已经过去了#。

答案 1 :(得分:1)

  

但事实证明,每过一段时间就会少于200毫秒。

我无法重现您的结果(既不是本地的,也不是指向dotnetfiddle.net的链接), 但无论如何Thread.Sleep看起来并不准确。参见例如How accurate is Thread.Sleep(TimeSpan)?

可能有点偏离主题,但对于 WINAPI Sleep函数MSDN says(强调我的):

  

系统时钟&#34;滴答&#34;以恒定的速度。如果dwMilliseconds小于系统时钟的分辨率,则线程可能会睡眠时间少于指定的时间长度。如果dwMilliseconds大于一个刻度但小于两个,则等待可以在一到两个刻度之间的任何位置,依此类推。


  

这很简单,因为这会定期返回负面结果。

DateTime.Now.Millisecond不返回毫秒,只返回毫秒组件。