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),
但无论如何,线程睡眠看起来并不准确。见例
可能有点离题,但对于WINAPISleep
函数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);
}