Java编译速度vs Scala编译速度

我一直在Scala编程一段时间,我喜欢它,但有一件事我很烦恼是编译程序所花费的时间。 这看起来像一个小东西,但与Java我可以做一些小的改变,我的程序,点击运行button在netbeans和BOOM,它正在运行,随着时间的推移在scala编译似乎要消耗大量的时间。 我听说有很多大型项目,由于编译时间的缘故,脚本语言变得非常重要,这是我在使用Java时没有看到的需求。

但是我从Java那里得知,据我所知,它比任何其他编译语言都快,而且由于我转向Scala(这是一种非常简单的语言)的原因,所以速度很快。

所以我想问一下,我可以让Scala编译得更快,并且可以和javac一样快。

Scala编译器比Java更复杂,提供了types推断,隐式转换和更强大的types系统。 这些function不是免费的,所以我不会期望scalac像javac一样快。 这反映了做这项工作的程序员和编译工作的权衡。

也就是说,从Scala 2.7到Scala 2.8的编译时间已经有了明显的提高,而且我预计现在灰尘已经稳定在2.8了。 本页介绍了一些正在进行的努力和想法,以提高Scala编译器的性能。

Martin Odersky在答复中提供了更多的细节。

Scala编译器有两个方面(缺less)速度。

  1. 更大的启动开销

    • Scalac本身由许多必须加载和jit编译的类组成

    • Scalac必须search类path中的所有根包和文件。 根据类path的大小,这可能需要一到三秒的时间。

    总的来说,如果你第一次运行scalac,启动开销会达到4-8秒,所以磁盘caching没有被填满。

    Scala对启动开销的回答是要么使用fsc,要么使用sbt进行连续的构build。 IntelliJ需要configuration使用任何一个选项,否则它的开销,即使对于小文件是不合理的大。

  2. 编译速度越慢。 Scalacpipe理大约500至1000行/秒。 Javacpipe理大约10倍。 这有几个原因。

    • types推断是昂贵的,特别是如果涉及隐式search。

    • Scalac必须做两次types检查; 一次根据斯卡拉的规则,第二次根据Java的规则擦除。

    • 除了types检查之外,从Scala到Java还有大约15个转换步骤,这都需要时间。

    • 对于给定的文件大小,Scala通常会比Java更多地生成类,特别是如果大量使用generics语言。 字节码生成和类写入需要时间。

    另一方面,一个1000行的Scala程序可能对应于2-3K行的Java程序,所以当以每秒行数计算时,一些较慢的速度必须与每行更多的function进行平衡。

    我们正在努力提高速度(例如通过并行生成类文件),但不能指望在这方面出现奇迹。 Scalac永远不会像javac那么快。 我相信这个解决scheme将会在像fsc这样的编译服务器上进行良好的依赖关系分析,以便只有最less的一组文件需要重新编译。 我们也在努力。

你应该知道,Scala编译至less比Java要长一个数量级来编译。 原因如下:

  1. 命名约定(文件XY.scala文件不需要包含一个名为XY的类,并且可能包含多个顶级类)。 因此,编译器可能需要search更多的源文件来查找给定的类/特征/对象标识符。
  2. 隐含 – 大量使用隐含意味着编译器需要search给定方法的任何范围内隐式转换,并对它们进行sorting以find“正确”的转换。 ( 即编译器在定位方法时有一个大量增加的search域。
  3. types系统 – scalatypes系统比Java更复杂,因此需要更多的CPU时间。
  4. types推断 – types推断在计算上是昂贵的,而javac根本不需要做的工作
  5. scalac包括一个全面武装和可操作战场的8位模拟器,可以在GenICode编译阶段使用魔术键组合CTRL-ALT-F12进行查看

做Scala的最好方法是使用IDEA和SBT。 build立一个基本的SBT项目(如果你愿意的话可以为你做),并以自动编译模式运行(命令~compile ),当你保存你的项目时,SBT会重新编译它。

您还可以使用适用于IDEA的SBT插件,并将SBT操作附加到每个运行configuration。 SBT插件还为您提供IDEA中的交互式SBT控制台。

无论哪种方式(SBT外部运行或SBT插件),SBT都会保持运行,因此所有用于构build项目的类都会“热身”,并且不需要启动开销。 另外,SBT只编译需要它的源文件。 这是构buildScala程序最有效的方法。

Scala-IDE (Eclipse)的最新版本在pipe理增量编译方面要好得多。

有关更多信息,请参阅“ 什么是最好的Scala构build系统?


另一个解决scheme是集成fsc – 用于Scala 2语言的快速脱机编译器 (如本博文中所述 )作为IDE中的构build器。

替代文字

但不是直接在Eclipse中,正如Daniel Spiewak在评论中提到的那样:

如果仅仅是因为Eclipse已经在表面下使用FSC,那么您不应该直接在Eclipse中使用FSC。
FSC基本上是驻留编译器的一个薄层,正是Eclipse用来编译Scala项目的机制。


最后,正如jackson·戴维斯在评论中提醒我的那样:

sbt(简单构build工具)也包括某种“增量”编译(通过触发执行 ),尽pipe它并不完美 ,而增强型编译正在为即将到来的0.9 sbt版本工作。

使用fsc – 这是一个快速的scala编译器,它作为后台任务,不需要一直加载。 它可以重用以前的编译器实例。

我不确定Netbeans scala插件是否支持fsc(文档中是这样说的),但是我无法使其工作。 尝试每晚构build的插件。

您可以使用Scala免费的JRebel插件。 所以你可以“在debugging器中开发”,JRebel将总是重新加载已更改的类。

我在Martin Odersky的某个地方读到了一些陈述,他说,searchimplicits(编译器必须确保在相同的转换中隐含不止一个单独的含义以排除歧义)可以使编译器保持繁忙。 所以小心处理暗示可能是个好主意。

如果它不一定是100%的斯卡拉,但也有类似的东西,你可以试试Kotlin 。

– 奥利弗

我相信这个结果会被低估,但是非常迅速的反转并不总是有利于质量或生产力。

花点时间仔细思考,less执行微循环。 良好的Scala代码更密集,更重要(即免除附带的细节和复杂性)。 这需要更多的思考,这需要时间(至less在第一时间)。 您可以使用更less的代码/testing/debugging周期来获得更好的性能,这些代码/testing/debugging周期会稍长一些,仍然可以提高您的工作效率和工作质量

简而言之:寻求更适合Scala的最佳工作模式。