逻辑内联与调用方法的效率?

时间:2015-10-03 10:30:40

标签: java optimization profiling

我目前与我的第二年JAVA教授有分歧,我希望所有人都能帮忙解决:

我们开始使用的代码是:

   public T peek()
   {
       if (isEmpty())
       .........
   }
   public boolean isEmpty() 
   {
       return topIndex<0;
   }

她希望我们删除isEmpty()引用并将其代码直接放入if语句中(即将peek方法内容更改为: if(topIndex<0).......)和#34;使代码更有效率#34;。我认为a)运行时/编译时优化器很可能已内联 即使它没有isEmpty() call, b),在几乎所有情况下,5-10机器操作都可以忽略不计,并且c)它的风格很差,因为它使程序的可读性降低,变化不大。

所以,我想我的问题是: 与仅调用方法相比,内联逻辑是否有任何运行时效率? 我尝试过简单的分析技术(又名长循环和秒表),但测试尚无定论。

编辑:

感谢大家的回复!我很感谢你们所有的时间。此外,我感谢那些评论与我的教授争论的实用主义,特别是在没有数据的情况下这样做的人。 @Mike Dunlavey我很欣赏你作为前教授的见解以及你对适当编码顺序的建议。 @ya_pulser我特别感谢您花时间分享的分析建议和链接。

5 个答案:

答案 0 :(得分:9)

你对java代码行为的假设是正确的,但是对于没有数据的教授而言你是不礼貌的:)。没有数据的争论是没有意义的,用测量和图表来证明你的假设。

您可以使用JMH(http://openjdk.java.net/projects/code-tools/jmh/)创建一个小基准并衡量之间的差异:

  • 手工内联(删除isEmpty方法并将代码放在调用位置)
  • 由java jit编译器内联(100k(?)调用后的热点 - 请参阅jit print compilation output)
  • 完全禁用热点内联

请阅读http://www.oracle.com/technetwork/java/whitepaper-135217.html#method

有用的参数可能是:

  • -Djava.compiler = NONE
  • -XX:+ PrintCompilation

另外每个jdk版本都有自己的一组参数来控制jit。

如果您将创建一些图形作为您的研究结果并将礼貌地呈现给教授 - 我认为它将来会对您有所帮助。

我认为https://stackoverflow.com/users/2613885/aleksey-shipilev可以帮助解决与jmh相关的问题。

BTW:当我将大量方法编入单个巨大的代码循环以实现神经网络反向传播例程的最大速度时,我取得了巨大的成功,因为java(使用方法的方法)对内联方法过于懒惰。这是不可维护和快速的:(。

答案 1 :(得分:8)

悲伤...

我同意你的直觉,特别是&#34;几乎在所有情况下,5-10机器操作都可以忽略不计。&#34;

很久以前我是C.S.教授。 一方面,教授们需要你能给予他们的一切懈怠。 教学要求很高。你不会有糟糕的一天。 如果你出现在课堂上并且你没有做好充分的准备,那么你就是一个艰难的旅程。 如果你在星期五进行考试并且周一没有成绩,那么学生会说'#34;但是你整个周末都有!&#34; 你可以从看到你的学生学到的东西中获得满足感,但除了如何教学之外,你自己并不学到很多东西。

另一方面,很少有教授对真实软件有很多实践经验。 因此,他们的观点倾向于建立在各种教条的证据上,而不是坚实的实用主义。

性能就是一个很好的例子。 他们倾向于说'不要做X.做Y因为它表现更好。&#34;这完全忽略了关于性能问题的观点 - 你必须处理分数,而不是 absolutes 。一切都取决于 else 正在发生什么。 接近表现的方式是,正如有人所说的那样#34;首先要做到正确。 然后让它快速。&#34;

你加快速度的方式不是通过观察代码(并且想知道&#34;我应该这样做,还是应该这样做&#34;),而是通过运行它并让它告诉你它是如何&# 39;花时间。 profiling 的基本思想是你如何做到这一点。 现在有一个糟糕的剖析和良好的剖析,as explained in the second answer here(通常当教授教导剖析时,他们教导的是坏的),但这是通往去。

答案 2 :(得分:5)

正如您所说,差异很小,在大多数情况下,可读性应该是更高的优先级。在这种情况下,由于额外的方法由一行组成,我不确定这会增加任何真正的可读性好处,除非你从其他地方调用相同的方法。

尽管如此,请记住,您的讲师的目标是帮助您学习计算机科学,这与编写生产代码不同。特别是,她不希望您将优化留给自动化工具,因为这对您的学习没有帮助。

另外,只是一个实用的注释 - 在学校和专业发展中,我们都必须遵守我们个人不同意的编码标准。这是一项重要的技能,对于团队合作来说确实是必要的,即使它确实很糟糕。

答案 3 :(得分:3)

调用isEmpty是惯用的,可读性很好。 手动内联这将是一个微优化, 在性能危急情况下最好的事情, 并且在预期的生产环境中通过基准确认瓶颈后。

手动内联是否有真正的性能优势? 理论上是的,也许这就是讲座想要强调的内容。 在实践中, 我不认为你会找到一个绝对的答案。 自动内联行为可能依赖于实现。 还要记住,基准测试结果将取决于JVM实现,版本,平台。 因此, 这种优化在极少数极端情况下非常有用, 并且通常不利于可移植性和可维护性。

按照同样的逻辑,我们应该内联所有方法, 以重复大块代码为代价消除所有间接? 当然不。 你在分解和内联之间准确划线的地方也可能取决于个人品味, 在某种程度上。

答案 4 :(得分:0)

要查看的另一种形式的数据可能是生成的代码。请参阅-XX:+PrintAssembly选项和朋友。有关详细信息,请参阅How to see JIT-compiled code in JVM?

我确信在这种特殊情况下,Hotspot JVM会内联isEmpty的调用,并且没有性能差异。