[ACCEPTED]-Is there any performance difference between ++i and i++ in C#?-performance

Accepted answer
Score: 41

There is no difference in the generated 13 intermediate code for ++i and i++ in this 12 case. Given this program:

class Program
{
    const int counter = 1024 * 1024;
    static void Main(string[] args)
    {
        for (int i = 0; i < counter; ++i)
        {
            Console.WriteLine(i);
        }

        for (int i = 0; i < counter; i++)
        {
            Console.WriteLine(i);
        }
    }
}

The generated 11 IL code is the same for both loops:

  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  // Start of first loop
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.0
  IL_0004:  br.s       IL_0010
  IL_0006:  ldloc.0
  IL_0007:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000c:  ldloc.0
  IL_000d:  ldc.i4.1
  IL_000e:  add
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  ldc.i4     0x100000
  IL_0016:  blt.s      IL_0006
  // Start of second loop
  IL_0018:  ldc.i4.0
  IL_0019:  stloc.0
  IL_001a:  br.s       IL_0026
  IL_001c:  ldloc.0
  IL_001d:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0022:  ldloc.0
  IL_0023:  ldc.i4.1
  IL_0024:  add
  IL_0025:  stloc.0
  IL_0026:  ldloc.0
  IL_0027:  ldc.i4     0x100000
  IL_002c:  blt.s      IL_001c
  IL_002e:  ret

That 10 said, it's possible (although highly unlikely) that 9 the JIT compiler can do some optimizations 8 in certain contexts that will favor one 7 version over the other. If there is such 6 an optimization, though, it would likely 5 only affect the final (or perhaps the first) iteration 4 of a loop.

In short, there will be no difference 3 in the runtime of simple pre-increment or 2 post-increment of the control variable in 1 the looping construct that you've described.

Score: 8

If you're asking this question, you're trying 13 to solve the wrong problem.

The first question 12 to ask is "how to I improve customer 11 satisfaction with my software by making 10 it run faster?" and the answer is almost 9 never "use ++i instead of i++" or 8 vice versa.

From Coding Horror's post "Hardware is Cheap, Programmers are Expensive":

Rules 7 of Optimization:
Rule 1: Don't do it.
Rule 6 2 (for experts only): Don't do it yet.
-- M.A. Jackson

I 5 read rule 2 to mean "first write clean, clear 4 code that meets your customer's needs, then 3 speed it up where it's too slow". It's 2 highly unlikely that ++i vs. i++ is going to be 1 the solution.

Score: 7

Ah... Open again. OK. Here's the deal.

ILDASM 34 is a start, but not an end. The key is: What 33 will the JIT generate for assembly code?

Here's 32 what you want to do.

Take a couple samples 31 of what you are trying to look at. Obviously 30 you can wall-clock time them if you want 29 - but I assume you want to know more than 28 that.

Here's what's not obvious. The C# compiler 27 generates some MSIL sequences that are non-optimal 26 in a lot of situations. The JIT it tuned 25 to deal with these and quirks from other 24 languages. The problem: Only 'quirks' someone 23 has noticed have been tuned.

You really want 22 to make a sample that has your implementations 21 to try, returns back up to main (or wherever), Sleep()s, or 20 something where you can attach a debugger, then 19 run the routines again.

You DO NOT want to 18 start the code under the debugger or the 17 JIT will generate non-optimized code - and 16 it sounds like you want to know how it will 15 behave in a real environment. The JIT does 14 this to maximize debug info and minimize 13 the current source location from 'jumping 12 around'. Never start a perf evaluation 11 under the debugger.

OK. So once the code 10 has run once (ie: The JIT has generated 9 code for it), then attach the debugger during 8 the sleep (or whatever). Then look at the 7 x86/x64 that was generated for the two routines.

My 6 gut tells me that if you are using ++i/i++ as 5 you described - ie: in a stand alone expression 4 where the rvalue result is not re-used - there 3 won't be a difference. But won't it be 2 fun to go find out and see all the neat 1 stuff! :)

Score: 7

As Jim Mischel has shown, the compiler will generate 10 identical MSIL for the two ways of writing 9 the for-loop.

But that is it then: there 8 is no reason to speculate about the JIT 7 or perform speed-measurements. If the two 6 lines of code generate identical MSIL, not 5 only will they perform identically, they 4 are effectively identical.

No possible JIT 3 would be able to distinguish between the 2 loops, so the generated machine code must 1 necessarily be identical, too.

Score: 3

Have a concrete piece of code and CLR release 4 in mind? If so, benchmark it. If not, forget 3 about it. Micro-optimization, and all that... Besides, you 2 can't even be sure different CLR release 1 will produce the same result.

Score: 2

In addition to other answers, there can 5 be a difference if your i is not an int. In C++, if it is an object of 4 a class that has operators ++() and ++(int) overloaded, then 3 it can make a difference, and possibly a 2 side effect. Performance of ++i should be better 1 in this case (dependant on the implementation).

Score: 0

According to this answer, i++ uses one CPU instruction 6 more than ++i. But whether this results 5 in a performance difference, I don't know.

Since 4 either loop can easily be rewritten to use 3 either a post-increment or a pre-increment, I 2 guess that the compiler will always use 1 the more efficient version.

Score: 0
  static void Main(string[] args) {
     var sw = new Stopwatch(); sw.Start();
     for (int i = 0; i < 2000000000; ++i) { }
     //int i = 0;
     //while (i < 2000000000){++i;}
     Console.WriteLine(sw.ElapsedMilliseconds);

Average from 3 runs:
for with i++: 1307 for 9 with ++i: 1314

while with i++ : 1261 while 8 with ++i : 1276

That's a Celeron D at 2,53 7 Ghz. Each iteration took about 1.6 CPU cycles. That 6 either means that the CPU was executing 5 more than 1 instruction each cycle or that 4 the JIT compiler unrolled the loops. The 3 difference between i++ and ++i was only 2 0.01 CPU cycles per iteration, probably 1 caused by the OS services in the background.

More Related questions