Overriding与if语句的性能

时间:2011-10-31 18:38:52

标签: java performance oop if-statement

我正在扩展和改进Java application,它还使用小型DSL进行长时间搜索(详细地说,它用于模型查找,是的,它通常是NP-Complete)。

在此搜索过程中,我想在控制台上显示一个小进度条。由于DSL的通用结构,我无法计算整体搜索空间大小。因此,我只能输出第一个“回溯”声明的进度。

现在的问题是: 我可以为每个回溯语句使用一个标志来指示此语句应该报告进度。在评估语句时,我可以用if语句检查标志:

public class EvalStatement {
  boolean reportProgress;

  public EvalStatement(boolean report) {
     reportProgress = report;
  }

  public void evaluate() {
    int progress = 0;

    while(someCondition) {
      // do something

      // maybe call other statement (tree structure)

      if (reportProgress) {
         // This is only executed by the root node, i. e.,
         // the condition is only true for about 30 times whereas
         // it is false millions or billions of times
         ++progress;
         reportProgress(progress);
      }
    }
  }
}

我也可以使用两个不同的类:

  • 什么都不做的课
  • 正在执行输出的子类

这看起来像这样:

public class EvalStatement {
  private ProgressWriter out;
  public EvalStatement(boolean report) {
      if (report)
        out = new ProgressWriterOut();
      else
        out = ProgressWriter.instance;     
  }
  public void evaluate() {
    while(someCondition) {
      // do something
      // maybe call other statement (tree structure)
      out.reportProgress(progress);
    }
  }
}

public class ProgressWriter {
  public static ProgressWriter instance = new ProgressWriter();
  public void reportProgress(int progress) {}
}

public class ProgressWriterOut extends ProgressWriter {
  int progress = 0;
  public void reportProgress(int progress) {
    // This is only executed by the root node, i. e.,
    // the condition is only true for about 30 times whereas
    // it is false millions or billions of times
    ++progress;
    // Put progress anywhere, e. g., 
    System.out.print('#');
  }
}

现在真正的问题是:

  • 方法的Java查找是否比if语句更快地调用?
  • 此外,接口和两个独立类会更快吗?

我知道Log4J建议在日志调用周围加一个if语句,但我认为主要原因是构造参数,特别是字符串。我只有原始类型。

修改: 我澄清了一点代码(经常被称为......单例的使用与此无关)。

此外,我进行了两次搜索的长期运行,其中if-statement和操作调用分别在一台机器上执行了1.840.306.311次:

  • if版本耗时10h 6分13秒(每秒50.343次点击)
  • or版本耗时10小时9分15秒(每秒50.595次点击)

我想说,这并没有给出真正的答案,因为0.5%的差异在于测量公差。

我的结论:他们或多或少的行为相同,但是从凯恩的答案中猜测,最重要的方法可能在长期内更快。

5 个答案:

答案 0 :(得分:5)

我认为这是过度优化的教科书定义。您甚至不确定自己是否存在性能问题。除非您在该部分中进行了数百万次呼叫,否则如果您对其进行了分析,它甚至都不会显示在您的热点报告中。如果语句和方法调用大约需要纳秒才能执行。因此,为了使它们之间存在差异,您最多只能节省1-10ns。对于那甚至被人类认为是慢的,它需要在100毫秒的量级,并且如果他们的用户甚至像主动点击等那样关注,如果他们正在观看进度条他们不是甚至会注意到它。

假设我们想看看是否增加了1秒的额外时间,你发现其中一个可以节省10秒(这可能节省了1-4ns)。这意味着你需要将该部分称为100,000,000次以节省1s。我可以保证,如果你有1亿个电话,你会发现其他10个区域比那里的if或polymorphism更昂贵。看起来愚蠢地讨论10ns的优点,你可能会节省1s不是吗?

我更关心你使用单身而不是表现。

答案 1 :(得分:2)

我不担心这个 - 成本非常小,输出到屏幕或计算会慢得多。

答案 2 :(得分:1)

我认为方法查找比评估if()更快。实际上,if的版本也需要方法查找。 如果你真的想要挤出每一点性能,在你的ProgessWriter中使用私有final方法,因为这可以允许JVM内联方法,所以不会有方法查找,甚至没有方法查找在最终编译之后调用从字节代码派生的机器代码。

但是,他们可能在性能上相当接近。我建议测试/简介,然后专注于真正的性能问题。

答案 3 :(得分:1)

真正回答这个问题的唯一方法是尝试两种方法并在正常情况下分析代码。有很多变数。

那就是说,如果我不得不猜测,我会说以下内容:

通常,if语句编译为比方法调用更少的字节码,但是通过JIT编译器优化,您的方法调用可能会被内联,这不是字节码。此外,通过if语句的分支预测,成本很低。

同样,一般,使用接口将比测试每次循环运行时报告更快。从长远来看,加载两个类,测试一次,并实例化一个类的成本,将比运行特定测试少一十万亿次。从长远来看。

同样,更好的方法是在两种方式上分析现实世界中的代码,甚至可以报告您的结果。但是,我很难看到这是您的应用程序的性能瓶颈......如果速度是一个问题,那么您在其他地方优化的时间可能会更好。

答案 4 :(得分:1)

将任何内容放在显示器上的速度比任一选择都慢几个数量级。如果您确实遇到了性能问题(我怀疑),您需要减少对print的调用次数。