【问题标题】:Elapsed time measurements bugs经过时间测量错误
【发布时间】:2014-07-16 23:19:06
【问题描述】:

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

我从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 对这个话题有所启发,但那里的 cmets 看起来有点矛盾。

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

编辑2:
根据建议,我决定使用 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,如果您需要在测量之间更改天数。

【问题讨论】:

  • Thread.Sleep 是出了名的不准确,请参阅stackoverflow.com/questions/12321225/…
  • @Alex 我最初使用了System.Threading.Timer,它显示了相同的结果,所以为了节省空间,我决定在示例中使用Thread.Sleep
  • 相同的答案,请参见此处:stackoverflow.com/questions/3744032/…。我认为它只睡了大约 200 毫秒,这有时意味着更少。
  • 我无法重现第一个问题。对我来说 stopwatch.ElapsedMilliseconds 到目前为止返回值 &gt;= 200
  • 你想在哪里获得 200,400,600,...等等?

标签: c# datetime stopwatch


【解决方案1】:

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

广告 2:使用 DateTime.Ticks (http://msdn.microsoft.com/en-us/library/system.datetime.ticks(v=vs.110).aspx),它返回“从时间开始”过去的“滴答声”(100ns 间隔)的数量。

【讨论】:

  • 就像我说的,Thread.Sleep 只是为了节省问题空间。最初它是 System.Theading.Timer。你知道吗,Timer 和 Thread.Sleep 有同样的问题吗?
【解决方案2】:

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

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

可能有点跑题了,但是对于 WINAPI Sleep 函数 MSDN says(强调我的):

系统时钟以恒定速率“滴答”。如果dwMilliseconds 小于系统时钟的分辨率,则线程可能休眠的时间少于指定的时间长度。如果dwMilliseconds 大于一个滴答但小于两个滴答,则等待可以介于一到两个滴答之间,依此类推。


像这样简单的事情通常会返回负面结果。

DateTime.Now.Millisecond 不返回 total 毫秒,只是毫秒分量。

【讨论】:

  • 没错,我的错。这可能会被取消
猜你喜欢
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
  • 2014-09-05
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
相关资源
最近更新 更多