Home>
What i am wondering

I was writing a console application in C #.
Some of the programs used the Stopwatch class in iterations.
When I ran the program and measured it, the processing was slow only for the first time.

I want to know the reason why the processing is slow only for the first time.

What I tried

I made the source code of the following console application to find out the cause.
Instantiate Stopwatch, start measurement, display elapsed time, end measurement.
Just repeat the process 5 times.
At first glance, the processing is the same for all five times, so you will think that the displayed times will be almost the same.

result

Located in the debug console below.
The first time was 00: 00: 00.0000037.
After that, it became 00: 00: 00.0000002 and 00: 00: 00.0000001.
Obviously the process is slow only the first time.

Expected

I think the reason it's slow only the first time is because it includes the time to allocate memory for the stopwatch.
I think that it was not necessary to organize the memory to secure the memory of the sentence at the first time, and then to use the place used at the first time.

Source code
using System;
using System.Diagnostics;
namespace tester
{
    class Program
    {
        static void Main ()
        {
            for (int i = 0;i<5;i ++)
            {
                Stopwatch stopwatch = new Stopwatch ();
                stopwatch.Start ();
                Console.WriteLine (stopwatch.Elapsed.ToString ());
                stopwatch.Stop ();
            }
        }
    }
}
Debug console
00: 00: 00.0000037
00: 00: 00.0000002
00: 00: 00.0000002
00: 00: 00.0000001
00: 00: 00.0000002
Postscript. Further verification experiments were conducted

Incorporating Zuishin's opinion, we conducted additional experiments.

  • Experiments conducted
    1 --Do not use for.
    2 --Add Elapsed to List and then WirteLine.
    3 --Array instead of List
    4 --Build.
Additional experiment 1 Source code
using System.Diagnostics;
using System;
namespace tester
{
    class Program
    {
        static void Main ()
        {
            Stopwatch stopwatch1 = new Stopwatch ();
            stopwatch1.Restart ();
            Console.WriteLine (stopwatch1.Elapsed);
            Stopwatch stopwatch2 = new Stopwatch ();
            stopwatch2.Reset ();Console.WriteLine (stopwatch2.Elapsed);
            Stopwatch stopwatch3 = new Stopwatch ();
            stopwatch3.Reset ();
            Console.WriteLine (stopwatch3.Elapsed);
            Stopwatch stopwatch4 = new Stopwatch ();
            stopwatch4.Reset ();
            Console.WriteLine (stopwatch4.Elapsed);
            Stopwatch stopwatch5 = new Stopwatch ();
            stopwatch5.Reset ();
            Console.WriteLine (stopwatch5.Elapsed);
        }
    }
}
Additional Experiment 1 Debug Console
00: 00: 00.0000033
00:00:00
00:00:00
00:00:00
00:00:00

There was no difference from the beginning.
It was too early to display less than a second.

Additional experiment 2 source code
using System.Collections.Generic;
using System.Diagnostics;
using System;
namespace tester
{
    class Program
    {
        static void Main ()
        {
            List<TimeSpan>timeSpans = new List<TimeSpan>();
            for (int i = 0;i<5;i ++)
            {
                Stopwatch stopwatch = new Stopwatch ();
                stopwatch.Start ();
                timeSpans.Add (stopwatch.Elapsed);
                stopwatch.Stop ();
            }
            foreach (TimeSpan time in timeSpans)
            {
                Console.WriteLine (time);
            }
        }
    }
}
Additional Experiment 2 Debug Console
00: 00: 00.0000053
00: 00: 00.0000001
00: 00: 00.0000001
00: 00: 00.0000001
00: 00: 00.0000001

There was no difference from the beginning.

Additional experiment 3 source code
using System.Diagnostics;
using System;
namespace tester
{
    class Program
    {
        static void Main ()
        {
            TimeSpan [] timeSpans = new TimeSpan [5];
            for (int i = 0;i<5;i ++)
            {
                Stopwatch stopwatch = new Stopwatch ();stopwatch.Start ();
                timeSpans [i] = stopwatch.Elapsed;
                stopwatch.Stop ();
            }
            foreach (TimeSpan time in timeSpans)
            {
                Console.WriteLine (time);
            }
        }
    }
}
Additional Experiment 3 Debug Console
00: 00: 00.0000040
00:00:00
00: 00: 00.0000001
00: 00: 00.0000001
00:00:00

There was no difference from the beginning.

Additional experiment 4 source code
Same as the first
Additional Experiment 4 Console
00: 00: 00.0000017
00: 00: 00.0000001
00: 00: 00.0000001
00: 00: 00.0000001
00:00:00

It's faster than the beginning, but it's still slow at first.

Addendum (solved by this)

From radian's answer, it is expected that it will be faster if you use the Stopwatch class before for.
So I experimented with the following source code.

Additional experiment source code
using System.Diagnostics;
using System;
namespace tester
{
    class Program
    {
        static void Main ()
        {
            Stopwatch st = new Stopwatch ();
            st.Start ();
            _ = st.Elapsed;
            for (int i = 0;i<5;i ++)
            {
                Stopwatch stopwatch = new Stopwatch ();
                stopwatch.Start ();
                Console.WriteLine (stopwatch.Elapsed.ToString ());
            }
            Console.ReadLine ();
        }
    }
}
Additional experiment debug console
00: 00: 00.0000001
00: 00: 00.0000002
00: 00: 00.0000001
00: 00: 00.0000002
00: 00: 00.0000002

this is......!

The first time is faster.
Considering that the source code so far is JIT compilation for the first time, it is considered that the processing time was saved because the source code this time is done before for.

From these, it can be said that the reason why the first process in the iterative process is slower than the later process is that the JIT compilation is performed for the first time, so the first process takes time.

Thank you to everyone who cooperated with this issue.

environment

visual studio 2019
Microsoft.NET Core.App 3.1.1 Console Application

c#
  • Answer # 1

    JIT compilation
    The explanation of the behavior of JIT compilation here will be helpful.
    Native code is generated the first time the method is executed, which is likely to incur some overhead.

  • Answer # 2

    If the execution code is cached, it can be executed at high speed.
    The first run that isn't in the cache will definitely be slow.

    Other languages ​​like C # that precompile may be slow due to the initial processing.