SanVEE
SanVEE

Reputation: 2070

Why is the first iteration always faster then the next in a loop?

I would like to understand why the first iteration in the loop executes quicker than the rest.

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 );
}

When I execute the code I get the following:

enter image description here

Initially I thought it could be due to the accuracy factor of Stopwatch class, but then why is it applicable only to the first element? Correct me if I'm missing something.

Upvotes: 1

Views: 256

Answers (2)

Luaan
Luaan

Reputation: 63772

This is a very flawed benchmark. For one, Thread.Sleep does not guarantee you that you'll sleep for exactly 100ms. Try much longer sleeps and you'll see more consistent results.

So it might be even just scheduling - the next iterations are always just doing sleep after sleep. Since Sleep works thanks to the system interrupt clock, the sleeps after the first should take similar amount of time, while the first has to "sync up" with the clock first.

If you add another sleep before the cycle (and before starting the stopwatch), you'll likely get closer times for each of the iterations.

Or even better, don't use sleeps. If you use some actual CPU work instead, you'll avoid thread switches (provided you've got enough CPU to do that) and many other costs not associated with the cycle itself. For example,

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 );
}

This will give you much more consistent results, because it doesn't depend on the clock at all.

There's many other things that can complicate a benchmark like this, which is why benchmarks simply aren't done this way. There will always be deviations, and they can get rather big, especially on a system with a lot of work.

In other words, if you're getting differences in CPU work execution time on the scale of milliseconds, someone is stealing your work. There's nothing in a modern CPU that would account for such a huge difference just based on e.g. i++ being there or not.

I could describe a lot more issues with your code, but it probably isn't worth it. Just google for some best practices on CPU work benchmarking in C#, and you'll get much more worth out of it.

Oh, and just to help hammer the point home more, on my computer, the first tends to go anywhere from 99 up to 100. This would be highly unusual, since the default is 15.6ms, rather than 1ms, but the culprit is easily found - Chrome sets it to 1ms. Ouch.

Upvotes: 7

Peter Ritchie
Peter Ritchie

Reputation: 35869

What you're outputting for times is the total time elapsed since the start. so, time increasing by about 100ms is exactly what you should be expecting

But, when you use Thread.Sleep you're giving up control of the thread and maybe for something close to the time you've specified. That time will be in multiples of the system quantum--so, what you specify cannot possibly be exact. If other threads of higher priority are doing work, it's less likely that your thread will be given processor time at a granularity close to the time you've suggested.

Upvotes: 3

Related Questions