views:

1381

answers:

9

Is there any performance difference between using something like

for(int i = 0; i < 10; i++) { ... }

and

for(int i = 0; i < 10; ++i) { ... }

or is the compiler able to optimize in such a way that they are equally fast in the case where they are functionally equivalent?

Edit: This was asked because I had a discussion with a co-worker about it, not because I think its a useful optimization in any practical sense. It is largely academic.

A: 

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

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

M4N
+4  A: 

Guys, guys, the "answers" are for C and C++.

C# is a different animal.

Use ILDASM to look at the compiled output to verify if there is an MSIL difference.

dan
+5  A: 

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

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

Here's what you want to do.

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

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

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

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

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

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

Joe
That's very informative. Thank you!
Hosam Aly
+2  A: 

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

Michael Borgwardt
A: 
  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 with ++i: 1314

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

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

ggf31416
Check out how Davy Landman times his code here (in the second code block):http://stackoverflow.com/questions/419952/could-you-please-review-my-quick-int-parser-implementation#421693By setting process priority, affinity, and thread priority, you can get more accurate measurements.
Hosam Aly
+14  A: 

There is no difference in the generated intermediate code for ++i and i++ in this 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 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 said, it's possible (although highly unlikely) that the JIT compiler can do some optimizations in certain contexts that will favor one version over the other. If there is such an optimization, though, it would likely only affect the final (or perhaps the first) iteration of a loop.

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

Jim Mischel
++ Yes, there is no difference, and even if there were, the loop would have to be almost empty of code to notice the difference. In this particular code, the loop overhead is to the loop contents as "a lightning bug is to lightning". (Mark Twain quote)
Mike Dunlavey
+3  A: 

If you're asking this question, you're either trolling for reputation or trying to solve the wrong problem.

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

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

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

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

Jay Bazuzi
Amazing, isn't it? Best response here--and the only one necessary.
rp
I always like to say that Premature Optimization is like Premature Ejaculation, bad for everyone.
CalvinR
The question "which one is faster" never occurred to me. I always use `++i`. Why? Because I read *from left to right* and `++i` is read as "increment the value of `i`" and not "take `i` and increment its value". Since `++` is on the left side, I can see immediately what's going on, I don't need to move my eyeballs to the right :) If you have a long variable name, `++something` is much more readable.
Jabba
+1  A: 

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

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

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

Rasmus Faber
+2  A: 

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

Hosam Aly