Search code examples
javac#performance

Redundant/Better Performance Code VS Optimized/Less Performance Code


In my case, I'm using C#, but the concept of the question would apply to Java as well. Hopefully the answer would be generic enough to cover both languages. Otherwise it's better to split the question into two.

I've always thought of which one is a better practice.

Does the compiler take care of enhancing the 'second' code so its performance would be as good as the 'first' code?

Could it be worked around to get a 'better performance' and 'optimized' code at the same time?

Redundant/Better Performance Code:

string name = GetName(); // returned string could be empty
List<string> myListOfStrings = GetListOfStrings();
if(string.IsNullOrWhiteSpace(name)
{
    foreach(string s in myListOfStrings)
        Console.WriteLine(s);
}
else
{
    foreach(string s in myListOfStrings)
        Console.WriteLine(s + " (Name is: " + name);
}

Optimized/Less Performance Code:

string name = GetName(); // returned string could be empty
List<string> myListOfStrings = GetListOfStrings();

foreach(string s in myListOfStrings)
    Console.WriteLine(string.IsNullOrWhiteSpace(name) ? s : s + " (Name is: " + name);

Obviously the execution time of the 'first' code is less because it executes the condition 'string.IsNullOrWhiteSpace(name)' only once per loop. Whereas the 'second' code (which is nicer) executes the condition on every iteration.

Please consider a long loop execution time not a short one because I know that when it is short, the performance won't differ.


Solution

  • Does the compiler take care of enhancing the 'second' code so its performance would be as good as the 'first' code?

    No, it cannot.

    1. It doesn't know that the boolean expression will not change between iterations of the loop. It's possible for the code to not return the same value each time, so it is forced to perform the check in each iteration.

    2. It's also possible that the boolean expression could have side effects. In this case it doesn't, but there's no way for the compiler to know that. It's important that such side effects would be performed in order to meet the specs, so it needs to execute the check in each iteration.

    So, the next question you need to ask is, in a case such as this, is it important to perform the optimization that you've mentioned? In any situation I can imagine for the exact code you showed, probably not. The check is simply going to be so fast that it's almost certainly not going to be a bottleneck. If there are performance problems there are almost certainly bigger fish.

    That said, with only a few changes to the example it can be made to matter. If the boolean expression itself is computationally expensive (i.e. it is the result of a database call, a web service call, some expensive CPU computation, etc.) then it could be a performance optimization that matters. Another case to consider is what would happen if the boolean expression had side effects. What if it was a MoveNext call on an IEnumerator? If it was important that it only be executed exactly once because you don't want the side effects to happen N times then that makes this a very important issue.

    There are several possible solutions in such a case.

    The easiest is most likely to just compute the boolean expression once and then store it in a variable:

    bool someValue = ComputeComplexBooleanValue();
    foreach(var item in collection)
    {
        if(someValue)
            doStuff(item);
        else
            doOtherStuff(item);
    }
    

    If you want to execute the boolean value 0-1 times (i.e. avoid calling it even once in the event that the collection is empty) then we can use Lazy to lazily compute the value, but ensure it's still only computed at most one time:

    var someValue = new Lazy<bool>(() => ComputeComplexBooleanValue());
    foreach (var item in collection)
    {
        if (someValue.Value)
            doStuff(item);
        else
            doOtherStuff(item);
    }