[ACCEPTED]-Is there any performance difference between ++i and i++ in C#?-performance
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.
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.
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! :)
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.
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.
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).
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.
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
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.