Why does the second for loop always execute faster than the first one?

前端 未结 8 1228
日久生厌
日久生厌 2021-01-05 11:14

I was trying to figure out if a for loop was faster than a foreach loop and was using the System.Diagnostics classes to time the task. While running the test I noticed that

相关标签:
8条回答
  • 2021-01-05 12:04

    I wouldn't read too much into this - this isn't good profiling code for the following reasons
    1. DateTime isn't meant for profiling. You should use QueryPerformanceCounter or StopWatch which use the CPU hardware profile counters
    2. Console.WriteLine is a device method so there may be subtle effects such as buffering to take into account
    3. Running one iteration of each code block will never give you accurate results because your CPU does a lot of funky on the fly optimisation such as out of order execution and instruction scheduling
    4. Chances are the code that gets JITed for both code blocks is fairly similar so is likely to be in the instruction cache for the second code block

    To get a better idea of timing, I did the following

    1. Replaced the Console.WriteLine with a math expression ( e^num)
    2. I used QueryPerformanceCounter/QueryPerformanceTimer through P/Invoke
    3. I ran each code block 1 million times then averaged the results

    When I did that I got the following results:

    The for loop took 0.000676 milliseconds
    The foreach loop took 0.000653 milliseconds

    So foreach was very slightly faster but not by much

    I then did some further experiments and ran the foreach block first and the for block second
    When I did that I got the following results:

    The foreach loop took 0.000702 milliseconds
    The for loop took 0.000691 milliseconds

    Finally I ran both loops together twice i.e for + foreach then for + foreach again
    When I did that I got the following results:

    The foreach loop took 0.00140 milliseconds
    The for loop took 0.001385 milliseconds

    So basically it looks to me that whatever code you run second, runs very slightly faster but not enough to be of any significance.
    --Edit--
    Here are a couple of useful links
    How to time managed code using QueryPerformanceCounter
    The instruction cache
    Out of order execution

    0 讨论(0)
  • 2021-01-05 12:06

    I was just performing tests to get some real numbers, but in the meantime Gaz beat me to the answer - the call to Console.Writeline is jitted at the first call, so you pay that cost in the first loop.

    Just for information though - using a stopwatch rather than the datetime and measuring number of ticks:

    Without a call to Console.Writeline before the first loop the times were

    for: 16802
    foreach: 2282
    

    with a call to Console.Writeline they were

    for: 2729
    foreach: 2268
    

    Though these results were not consistently repeatable because of the limited number of runs, but the magnitude of difference was always roughly the same.


    The edited code for reference:

            int[] x = new int[] { 3, 6, 9, 12 };
            int[] y = new int[] { 3, 6, 9, 12 };
    
            Console.WriteLine("Hello World");
    
            Stopwatch sw = new Stopwatch();
    
            sw.Start();
            for (int i = 0; i < 4; i++)
            {
                Console.WriteLine(x[i]);
            }
            sw.Stop();
            long elapsedTime = sw.ElapsedTicks;
    
            sw.Reset();
            sw.Start();
            foreach (var item in y)
            {
                Console.WriteLine(item);
            }
            sw.Stop();
            long elapsedTime2 = sw.ElapsedTicks;
    
            Console.WriteLine("\nSummary");
            Console.WriteLine("--------------------------\n");
            Console.WriteLine("for:\t{0}\nforeach:\t{1}", elapsedTime, elapsedTime2);
    
            Console.ReadKey();
    
    0 讨论(0)
提交回复
热议问题