1

In a C# console application I have a loop that iterates through about 8000 items in a collection, setting about eight strings equal to various properties of the items and then using those strings to perform a big variety of other operations. To keep my code organized I'm declaring all of the strings ahead of time and leaving them null until an item is read and the loop sets the appropriate string equal to the appropriate value. My question is, will there be a noticeable performance difference between declaring those strings outside of the loop versus inside? I know it will technically eat up some extra clock cycles declaring them each time the loop iterates, and after 8000 iterations that might start to add up, but I have no idea how much or if it will even matter? This application already takes a good half hour to complete its full cycle so a couple seconds of difference is insignificant, but if we're talking minutes obviously that's a bad thing.

Please keep in mind this is mostly a question of curiosity, I could honestly declare these variables wherever without affecting the application. I'm sure best practices state that they should always be outside the loop, but I've always wondered how much of a difference it really makes in this kind of low-impact operation.

Servy
  • 202,030
  • 26
  • 332
  • 449
thanby
  • 323
  • 1
  • 6
  • 22
  • profile it and see. if can't be that hard to set up both options and then run it and see if you notice a difference – Sam Holder Mar 24 '14 at 13:34
  • 4
    "I know it will technically eat up some extra clock cycles declaring them each time the loop iterates" -- how do you know that? "I'm sure best practices state that they should always be outside the loop [...]" -- I'm pretty sure it's better practice to make their scope as small as possible, i.e., declare them *inside* the loop. –  Mar 24 '14 at 13:35
  • 1
    @delnan You're right, and really it's the *compiler's* job to perform the optimization of moving a declaration outside a loop. The optimizing compiler can and does perform that exact optimization sometimes, but I *have* seen cases where it fails to do so and doing it yourself has a significant impact on performance. But of course [optimization should only be done when necessary](http://programmers.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil) and then only after profiling has determined that it will have a significant effect. – TypeIA Mar 24 '14 at 14:03

3 Answers3

2

My question is, will there be a noticeable performance difference between declaring those strings outside of the loop versus inside?

No there won't. Your re-initializing the string inside the loop. If anything your making the program do more work by initializing the code outside the loop and then doing it again inside. I would guess that the compiler will optimize this away though.

I know it will technically eat up some extra clock cycles declaring them each time the loop iterates

You should just let the compiler do it's job and optimize it for you. Trying to do the compiler's work just frustrates you and makes it more difficult to optimize the code. This is most likely complete untrue also.

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
2

Firstly, 8000 is relatively small number for modern computers, so I wouldn't worry about little things like declaring variables or using properties as the difference would be negligible. I know a colleague who insisted on eliminating the use of properties when we were optimizing our code for an operation that took a few ours. I kept telling him that he was wasting our time on something negligible, but he succeeded in convincing the team and they conducted a test without me. The loop had 1 million iterations, yet the difference was hardly half a second.

Now in your case, I believe there will be actually no difference at all. And again, 8000 is too small to even bother thinking about the difference, if it exists.

As to the best practice, it is actually the other way around. The scope should be the smallest possible, so declare them inside the loop.

And here is a good test done by one of the SO users with full discussion.

Community
  • 1
  • 1
Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
  • 1
    That puts it into perspective, thanks! Half a second after a million iterations? I figured the change in my case would be insignificant but that's waaaaaay less of an impact that I would have imagined. – thanby Mar 24 '14 at 14:17
  • @thanby Yes, that was my goal in providing you with real-life example, to "put it into perspective". I was surprised too how little the difference was. I was dead sure it would be negligible, but expected it to be at least few seconds. – Racil Hilan Mar 24 '14 at 14:24
  • @thanby I've just found a good [test done by one of the SO users][1]. I thought of sharing it as it has useful discussion that complements my answer. – Racil Hilan Apr 03 '14 at 17:23
2

There will not be any difference (ok, should not be). At least, you should not even think about it - compiler optimization will do it for you.

Basically, when you assign new string value to variable, the following happens:

  • New string created in heap (unless it is interned - let's skip it for simplicity)
  • New string reference copied in the place of old string reference (reference variable in the stack)
  • Old string is not referred by anyone now, so it will be collected by Garbage Collector some time later

It does not really matter if you declare variable inside loop or outside loop - compiler (most probably) will just reuse the same stack area to keep reference to string in both cases.

Best practice is to declare variable in the inner most scope, that is, inside loop in your case.

EDIT:

Adding some exercises. Considering the following sample (notice how much code I had to write so that optimizer leave at least something for us):

internal class Program
{
    private static string InnerLoop()
    {
        var sb = new StringBuilder();

        string s;
        for (int i = 0; i < 8000; i++)
        {
            s = i.ToString();
            sb.Append(s);
        }

        return sb.ToString();
    }

    private static string OuterLoop()
    {
        var sb = new StringBuilder();

        for (int i = 0; i < 8000; i++)
        {
            string s;
            s = i.ToString();
            sb.Append(s);
        }

        return sb.ToString();
    }

    private static void Main(string[] args)
    {
        Console.WriteLine(InnerLoop());
        Console.WriteLine(OuterLoop());
    }
}

Build in Release, open with Reflector and see compiler optimizations in action:

enter image description here

You can play with your code in similar way.

Lanorkin
  • 7,310
  • 2
  • 42
  • 60
  • Great explanation, thank you! I forgot it's actually declaring a new string before assigning it to the old one anyways, that makes sense. – thanby Mar 24 '14 at 14:16