Is it faster to declare variables for loop criteria outside the loop condition?

In the following scenario, example 1 is faster than example 2? Why?

Example 1

int c = myArray.Count;
for (int i = 0; i < c; i++)
{
  Console.WriteLine(myArray[i]);
}

Example 2

for (int i = 0; i < myArray.Count; i++)
{
  Console.WriteLine(myArray[i]);
}
+4
source share
3 answers

Let's take the IL code and see what happens in the Release configuration.

    / * 0x0000027B 6F0D00000A * / IL_001F: callvirt instance int32 class [System.Collections] System.Collections.Generic.List`1 :: get_Count ()
    / * 0x00000280 0B * / IL_0024: stloc.1
    / * 0x00000281 16 * / IL_0025: ldc.i4.0
    / * 0x00000282 0C * / IL_0026: stloc.2
    / * 0x00000283 2B10 * / IL_0027: br.s IL_0039
    // loop start (head: IL_0039)
        / * 0x00000285 06 * / IL_0029: ldloc.0
        /* 0x00000286 08           */ IL_002A: ldloc.2
        /* 0x00000287 6F0E00000A   */ IL_002B: callvirt  instance !0 class [System.Collections]System.Collections.Generic.List`1::get_Item(int32)
        /* 0x0000028C 280F00000A   */ IL_0030: call      void [System.Console]System.Console::WriteLine(char)
        /* 0x00000291 08           */ IL_0035: ldloc.2
        /* 0x00000292 17           */ IL_0036: ldc.i4.1
        /* 0x00000293 58           */ IL_0037: add
        /* 0x00000294 0C           */ IL_0038: stloc.2

        /* 0x00000295 08           */ IL_0039: ldloc.2
        /* 0x00000296 07           */ IL_003A: ldloc.1
        /* 0x00000297 32EC         */ IL_003B: blt.s     IL_0029
    // end loop

    /* 0x00000299 16           */ IL_003D: ldc.i4.0
    /* 0x0000029A 0D           */ IL_003E: stloc.3
    /* 0x0000029B 2B10         */ IL_003F: br.s      IL_0051
    // loop start (head: IL_0051)
        /* 0x0000029D 06           */ IL_0041: ldloc.0
        /* 0x0000029E 09           */ IL_0042: ldloc.3
        /* 0x0000029F 6F0E00000A   */ IL_0043: callvirt  instance !0 class [System.Collections]System.Collections.Generic.List`1::get_Item(int32)
        /* 0x000002A4 280F00000A   */ IL_0048: call      void [System.Console]System.Console::WriteLine(char)
        /* 0x000002A9 09           */ IL_004D: ldloc.3
        /* 0x000002AA 17           */ IL_004E: ldc.i4.1
        /* 0x000002AB 58           */ IL_004F: add
        /* 0x000002AC 0D           */ IL_0050: stloc.3

        /* 0x000002AD 09           */ IL_0051: ldloc.3
        /* 0x000002AE 06           */ IL_0052: ldloc.0
        /* 0x000002AF 6F0D00000A   */ IL_0053: callvirt  instance int32 class [System.Collections]System.Collections.Generic.List`1::get_Count()
        /* 0x000002B4 32E7         */ IL_0058: blt.s     IL_0041
    // end loop

: virtual , - .

IL- , , , callvirt ( callvirt ? , , ) . , , , , , JIT - .


: BenchmarkDotNet .

       Method |     Mean |     Error |    StdDev |
------------- |---------:|----------:|----------:|
 OutsideCount | 25.04 ns | 0.3334 ns | 0.2955 ns |
  InsideCount | 26.13 ns | 0.5295 ns | 0.6502 ns |
      Foreach | 40.59 ns | 0.3848 ns | 0.3599 ns |

, , .

+4

. :

class WorkBench
{
    private static readonly Stopwatch S = new Stopwatch();

    private static long[] RunOnce()
    {
        var results = new long[3];
        var myArray = Enumerable.Range(0, 1000000).ToList();
        int x = 1;

        S.Restart();

        for (int i = 0; i < myArray.Count; i++)
        {
            x = i + 1;
        }

        S.Stop();

        results[0] = S.ElapsedTicks;

        S.Restart();

        int c = myArray.Count;
        for (int i = 0; i < c; i++)
        {
            x = i - 1;
        }

        S.Stop();
        results[1] = S.ElapsedTicks;
        results[2] = x;

        return results;
    }

    private static void Main(string[] args)
    {
        var results = new List<Tuple<long, long>>();

        for (int i = 0; i < 1500; i++)
        {
            var workBenchResult = RunOnce();
            results.Add(Tuple.Create(workBenchResult[0], workBenchResult[1]));
        }

        var average = Tuple.Create(results.Average(r => r.Item1), results.Average(r => r.Item2));

        Console.WriteLine($"Average 1: {Math.Round(average.Item1, 4)}");
        Console.WriteLine($"Average 2: {Math.Round(average.Item2, 4)}");
    }

:

DEBUG: 7852 6631 ( )

: 1117 1127 ( )

:

array (collection) , , .

, int .. , , , , , Count .

+3

Count Count(). 2, , , .

, Count ICollection Length array, .

0
source

Source: https://habr.com/ru/post/1695395/


All Articles