C# 运行时间测量错误

C# 运行时间测量错误,c#,datetime,stopwatch,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); } 像这样简单的事情经常会产生负面结果

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

我从
Stopwatch
课程开始:

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

像这样简单的事情经常会产生负面结果

所以我的问题是:这两个类出现这种行为的原因是什么?我如何更精确地测量经过的时间(没有负偏差)?
有一篇关于秒表的文章对这个话题有一定的启发,但是评论看起来有点矛盾

Edit1:
正如AlexD所发现的,
DateTime.Now.millished
只返回毫秒部分,而不是totalmillishes。这一点很清楚

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);    
}
for(int i=0;i<100;i++)
{
var start=(int)DateTime.UtcNow.TimeOfDay.totalmillizes;
睡眠(200);
var stop=(int)DateTime.UtcNow.TimeOfDay.totalmillizes;
控制台写入线(停止-启动);
}
或者
DateTime.UtcNow.Ticks/TimeSpan.tickspellsecond
,如果您需要在测量之间更改日期

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

我无法复制您的结果(既不能在本地复制,也不能链接到dotnetfiddle.net), 但无论如何,线程睡眠看起来并不准确。见例

可能有点离题,但对于WINAPI
Sleep
函数MSDN(我的重点):

系统时钟以恒定速率“滴答”作响。如果
dwmillizes
小于系统时钟的分辨率,则线程的睡眠时间可能小于指定的时间长度。如果
dw毫秒
大于一个刻度但小于两个刻度,则等待时间可以在一到两个刻度之间的任何位置,依此类推


像这样简单的事情经常会产生负面结果


DateTime.Now.millished
不返回总毫秒数,只返回毫秒分量。

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


Ad 2:使用DateTime.Ticks(),它返回“从时间开始”经过的“Ticks”(100ns间隔)数。

Thread.Sleep是出了名的不精确,请参阅@Alex我最初使用的
System.Threading.Timer
,它显示了相同的结果,所以我决定在节省空间的示例中使用
Thread.Sleep
,sakeSame答案,请参见此处:。我认为它只睡了大约200毫秒,这有时意味着少睡一点。我无法重现第一个问题。对我来说,
秒表。到目前为止,elapsedmillyseconds
返回值
=200
。你想从哪里得到200400600……等等?是的,我的错。这可能会像我说的那样,线程。睡眠只是为了节省问题空间。最初是System.Theading.Timer。你们知道吗,定时器和线程有同样的问题吗?睡眠?
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);    
}