冗余/更好的性能代码VS优化/更低性能代码

时间:2013-09-12 17:27:56

标签: c# java performance compiler-construction

就我而言,我使用的是C#,但问题的概念也适用于Java。希望答案足够通用,涵盖两种语言。否则最好将问题分成两部分。

我一直都在想哪一个是更好的做法。

编译器是否负责增强第二个'代码,所以它的性能将与第一个'一样好。码?

是否可以通过努力获得更好的性能' '优化'代码同时?

冗余/更好的性能代码:

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);
}

优化/减少效果代码:

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);

显然,第一个&#39;的执行时间。代码较少,因为它执行条件&#39; string.IsNullOrWhiteSpace(name)&#39;每个循环只有一次。而第二个&#39;代码(更好)在每次迭代时执行条件。

请考虑长循环执行时间而不是短循环,因为我知道当它很短时,性能不会有所不同。

2 个答案:

答案 0 :(得分:3)

  

编译器是否负责增强“第二个”代码,使其性能与“第一个”代码一样好?

不,它不能。

  1. 它不知道布尔表达式在循环的迭代之间不会改变。 可能代码每次都不返回相同的值,因此每次迭代都会强制执行检查。

  2. 布尔表达式也可能有副作用。在这种情况下它没有,但编译器无法知道这一点。为了满足规范,执行这样的副作用非常重要,因此需要在每次迭代中执行检查。

  3. 那么,您需要问的下一个问题是,在这种情况下,执行您提到的优化是重要吗?在任何情况下,我可以想象您显示的确切代码,可能不是。检查只是如此之快,以至于几乎肯定不会成为瓶颈。如果出现性能问题,几乎肯定会有更大的鱼。

    也就是说,只需对示例进行一些更改就可以了。如果布尔表达式本身在计算上很昂贵(即它是数据库调用,Web服务调用,一些昂贵的CPU计算等),那么它可能是一个重要的性能优化。另一个需要考虑的情况是,如果布尔表达式有副作用,会发生什么。如果是MoveNext IEnumerator来电话怎么办?如果重要的是它只执行一次,因为你不希望副作用发生N次,那么这就是非常重要的问题。

    在这种情况下有几种可能的解决方案。

    最简单的方法是最有可能只计算一次布尔表达式,然后将其存储在变量中:

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

    如果你想执行布尔值0-1次(即避免在集合为空的情况下调用它一次),那么我们可以使用Lazy来懒惰地计算值,但确保它仍然是最多只计算一次:

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

答案 1 :(得分:1)

您应该始终采用更容易理解和维护的方式。这意味着将重复代码减少到绝对最小值(DRY)。此外,这种微优化对许多系统来说并不重要。另请注意,较短的代码并不总是更好。

我想我会选择这样的话:

string name = GetName(); // returned string could be empty
bool nameIsEmpty = string.IsNullOrWhiteSpace(name);

foreach (string s in GetListOfStrings()) {       

    string messageAddition = "";
    if (!nameIsEmpty) {
        messageAddition = " (Name is: " + name + ")";
    }

    Console.WriteLine(s + messageAddition);

    // more code which uses the computed value.. 
    // otherwise the condition can be moved out the loop
}

我发现一个额外的if语句比方法调用中的?:运算符更容易阅读,但这可能是个人品味。

如果您想在以后提高性能,则应该对应用程序进行概要分析,并首先开始优化最慢的代码段。也许你的GetListOfStrings()方法太慢了,其他代码的性能完全无关紧要。如果你测量那么重复循环可以提高性能,你可以考虑改变它。