在经过时间测量过程中偶然发现意外行为。
我从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
如果测量之间的日期变化是您的情况。
答案 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
不返回总毫秒,只返回毫秒组件。