为什么第一次迭代总是比循环中的下一次更快?

时间:2014-09-30 15:07:39

标签: c# loops iteration

我想了解为什么循环中的first iteration执行速度比其他更快。

Stopwatch sw = new Stopwatch ();
sw.Start ();

for(int i=0; i<10; i++)
{
   System.Threading.Thread.Sleep ( 100 );
   Console.WriteLine ( "Finished at : {0}", ((double) sw.ElapsedTicks / Stopwatch.Frequency ) * 1e3 );
}

当我执行代码时,我得到以下内容:

enter image description here

最初我认为可能是由于Stopwatch类的准确性因素,但为什么它只适用于第一个元素?如果我错过了什么,请纠正我。

2 个答案:

答案 0 :(得分:7)

这是一个非常有缺陷的基准。例如,Thread.Sleep并不能保证你会睡100分钟。尝试更长时间的睡眠,你会看到更一致的结果。

所以它甚至可能只是调度 - 下一次迭代总是在睡眠后进行睡眠。由于Sleep由于系统中断时钟而起作用,因此在第一个之后的休眠应该花费相似的时间,而第一个必须首先与时钟“同步”。

如果你在周期之前(以及在开始秒表之前)添加另一个睡眠,你可能会在每次迭代中获得更接近的时间。

甚至更好,不要使用睡眠。如果您使用一些实际的CPU工作,您将避免线程切换(假设您有足够的CPU来执行此操作)以及许多其他与循环本身无关的成本。例如,

Stopwatch sw = new Stopwatch ();
sw.Start ();

for(int i=0; i<10; i++)
{
   Thread.SpinWait(10000000);

   Console.WriteLine ( "Finished at : {0}", ((double) sw.ElapsedTicks / Stopwatch.Frequency ) * 1e3 );
}

这将为您提供更加一致的结果,因为它根本不依赖于时钟。

还有许多其他因素可能会使这样的基准复杂化,这就是为什么基准测试不是这样做的原因。总是存在偏差,并且它们会变得相当大,特别是在具有大量工作的系统上。

换句话说,如果您在毫秒级别上获得CPU工作执行时间的差异,则有人会窃取您的工作。现代CPU中没有什么可以解释如此巨大的差异,仅仅基于例如i++是否存在。

我可以用你的代码描述更多问题,但它可能不值得。只需google了解C#中CPU工作基准测试的一些最佳实践,您就可以从中获得更多价值。

哦,只是为了帮助点回家更多,在我的电脑上,第一个往往从99100。这非常不寻常,因为默认值为15.6ms,而不是1ms,但很容易找到罪魁祸首 - Chrome将其设置为1ms。哎哟。

答案 1 :(得分:3)

您输出的次数是自启动以来经过的时间。所以,时间增加大约100毫秒正是你应该期待的

但是,当您使用Thread.Sleep时,您放弃了对该主题的控制权,并且可能接近您指定的时间。那个时间处于系统量子的倍数 - 所以,你指定的内容可能不准确。如果其他优先级较高的线程正在工作,那么您的线程不太可能以接近您建议的时间的粒度获得处理器时间。