清洁代码与性能

时间:2018-03-17 10:05:00

标签: java android compiler-optimization

clean code的一些原则是:

  • 函数应该在一个抽象级别做一件事
  • 功能最多应为20行
  • 函数不应超过2个输入参数

通过在Java中添加额外的函数调用来“丢失”多少个cpu周期? 是否有可用的编译器选项将许多小函数转换为一个大函数以优化性能?

E.g。

void foo() {
  bar1()
  bar2()
}

void bar1() {
  a();
  b();
}
void bar2() {
  c();
  d();
}

会变成

void foo() {
  a();
  b();
  c();
  d();
}

3 个答案:

答案 0 :(得分:1)

  

通过在Java中添加额外的函数调用来“丢失”多少个cpu周期?

这取决于它是否内联。如果它是内联的,它将不会是任何东西(或名义上的数量)

如果它不是在运行时编译的,那么它几乎不重要,因为数据库的成本比微优化更重要,并且很可能没有被称为足够重要(这就是它没有被优化的原因)

唯一真正重要的是经常调用代码时,但由于某种原因,它无法进行优化。我只是假设情况就是这样,因为你有一个分析器告诉你这是一个性能问题,在这种情况下手动内联可能就是答案。

我在Java中设计,开发和优化延迟敏感代码,我选择手动内联方法的时间远远少于1%,但仅限于分析器,例如飞行记录器表明存在严重的性能问题。

  

在极少数情况下,重要的是它有多大差异?

对于每个额外的通话,我估计实际应用中的微秒级在0.03到0.1微秒之间,在微基准测试中它会少得多。

  

是否有可用的编译器选项将许多小函数转换为一个大函数以优化性能?

是的,事实上可能发生的不仅是所有这些方法都被内联,而且调用它们的方法也被内联,并且它们在运行时都不重要,但只有在调用代码足以进行优化时才会这样。即不仅内联abcd,而且代码foo也会被内联。

通过 default ,Oracle JVM可以排列到9个级别的深度(直到代码获得超过325个字节的字节代码)

  

清理代码有助于提高性能

JVM运行时优化器具有针对其优化的常见模式。干净,简单的代码通常更容易优化,当你尝试一些棘手或不明显的东西时,你最终可能会慢得多。如果对人类更难理解,优化者很难理解/优化。

答案 1 :(得分:0)

运行时行为和代码的清晰度(代码的编译时间或生命周期属性)属于不同的需求类别。可能存在这样的情况:优化一个类别对另一个类别是有害的。

问题是:哪个类别真的需要你关注?

在我看来,代码的清洁度(或软件的可塑性)受到严重缺乏关注。你应该首先关注它。并且只有当其他要求开始落后(例如性能)时,才会询问是否由于代码的清洁程度而导致的。这意味着你需要真正比较,你需要衡量它所带来的差异。关于性能使用您选择的分析器:运行"脏"代码变体和干净的变体,并检查差异。它明显吗?只有"脏"如果降低清洁度,变体会明显加快。

答案 2 :(得分:0)

请考虑以下代码,该代码将一个在一个for循环中执行3件事的代码与另一个在每个任务中具有3个不同的for循环的代码进行比较。

  @Test
  public void singleLoopVsMultiple() {
    for (int j = 0; j < 5; j++) {

      //single loop
      int x = 0, y = 0, z = 0;
      long l = System.currentTimeMillis();
      for (int i = 0; i < 100000000; i++) {
        x++;
        y++;
        z++;
      }
      l = System.currentTimeMillis() - l;


      //multiple loops doing the same thing
      int a = 0, b = 0, c = 0;
      long m = System.currentTimeMillis();
      for (int i = 0; i < 100000000; i++) {
        a++;
      }
      for (int i = 0; i < 100000000; i++) {
        b++;
      }
      for (int i = 0; i < 100000000; i++) {
        c++;
      }
      m = System.currentTimeMillis() - m;
      System.out.println(String.format("%d,%d", l, m));

    }
  }

当我运行它时,这是我获得的时间(以毫秒为单位)。

6,5
8,0
0,0
0,0
0,0

运行几次后,JVM能够识别密集代码的热点,并优化部分代码以使其变得更快。在我们之前的示例中,运行2次后,JVM已经对代码进行了优化,以至于围绕for循环的讨论变得多余了。

除非我们知道内部发生了什么,否则我们无法预测诸如引入for循环之类的更改对性能的影响。真正提高系统性能的唯一方法是测量系统并仅专注于解决实际瓶颈。

清理代码有可能使JVM更快。但是,即使不是这种情况,每次性能优化都会增加代码的复杂性。问问自己,增加的复杂性是否值得将来进行维护。毕竟,任何团队中最昂贵的资源是开发人员,而不是服务器,并且任何其他复杂性都会降低开发人员的速度,从而增加项目成本。

处理该问题的方法是弄清基准,正在开发的应用程序类型,瓶颈是什么。如果您正在制作一个Web应用程序,那么数据库可能会花费大部分时间,并且减少功能数量不会有什么不同。另一方面,如果它的应用程序在性能至关重要的系统上运行,那么每个小事都很重要。