Java编译速度与Scala编译速度

时间:2010-08-16 03:22:57

标签: java performance scala compilation

我已经在Scala中编程了一段时间,我喜欢它,但有一点我很烦恼的是编译程序所需的时间。这似乎是一个小东西,但是使用Java我可以对我的程序进行小的更改,单击netbeans中的运行按钮,然后运行BOOM,并且随着时间的推移在scala中编译似乎消耗了大量时间。我听说在许多大项目中,脚本语言因为编译时间变得非常重要,我在使用Java时没有看到这种需求。

但是我来自Java,据我所知,它比任何其他编译语言都快,并且由于我切换到Scala的原因很快(这是一种非常简单的语言)。

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

8 个答案:

答案 0 :(得分:449)

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

  1. 更大的启动开销

    • Scalac本身包含很多必须加载和编译的类

    • Scalac必须在类路径中搜索所有根包和文件。根据类路径的大小,这可能需要一到三秒钟。

    总的来说,期望scalac的启动开销为4-8秒,如果你第一次运行它会更长,因此磁盘缓存没有被填充。

    Scala对启动开销的回答是使用fsc或者使用sbt进行连续构建。 IntelliJ需要配置为使用任一选项,否则即使是小文件的开销也不合理。

  2. 编译速度较慢。 Scalac管理大约500到1000线/秒。 Javac管理的次数约为10倍。这有几个原因。

    • 类型推断成本很高,特别是如果它涉及隐式搜索。

    • Scalac必须进行两次类型检查;一次根据Scala的规则,根据Java规则擦除后第二次。

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

    • Scala通常会为每个给定文件大小生成比Java更多的类,特别是如果大量使用功能习惯用法。字节码生成和课堂写作需要时间。

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

    我们正在努力提高速度(例如通过并行生成类文件),但人们不能指望这方面的奇迹。 Scalac永远不会像javac一样快。 我相信解决方案将在于像fsc这样的编译服务器以及良好的依赖性分析,因此只需要重新编译最小的文件集。我们也在努力。

答案 1 :(得分:55)

Scala编译器比Java更复杂,提供类型推断,隐式转换和更强大的类型系统。这些功能不是免费的,所以我不希望scalac像javac一样快。这反映了执行工作的程序员与编写工作的编译器之间的权衡。

也就是说,从Scala 2.7到Scala 2.8的编译时间已经明显改善,而且我预计这些改进将继续下去,因为尘埃落定在2.8上。 This page记录了一些正在进行的改进Scala编译器性能的努力和想法。

Martin Odersky provides much more detail in his answer.

答案 2 :(得分:40)

您应该知道,Scala编译至少比编译Java的时间长一个数量级。原因如下:

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

答案 3 :(得分:19)

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

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

无论哪种方式(SBT外部运行或SBT插件),SBT都会继续运行,因此构建项目时使用的所有类都会“预热”并进行JIT编辑,从而消除了启动开销。此外,SBT仅编译需要它的源文件。它是迄今为止构建Scala程序的最有效方法。

答案 4 :(得分:8)

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

有关详情,请参阅“What’s the best Scala build system?”。


另一个解决方案是将fsc - Fast offline compiler for the Scala 2 language - (如此blog post中所示)作为IDE中的构建器进行集成。

alt text

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

  

你不应该直接在Eclipse中使用FSC,只是因为Eclipse已经在表面下使用了FSC   FSC基本上是驻留编译器之上的一个薄层,它正是Eclipse用来编译Scala项目的机制。


最后,正如Jackson Davis在评论中提醒我的那样:

sbt (Simple build Tool)还包括某种“增量”编译(通过triggered execution),即使它is not perfect,并且增强的增量编译正在为即将到来的0.9 sbt版本工作。

答案 5 :(得分:6)

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

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

答案 6 :(得分:3)

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

我在Martin Odersky自己的某处读到了一些声明,他说的是对implicits的搜索(编译器必须确保同一转换中隐含的多个单一内容以排除歧义)可以使编译器保持忙碌状态。因此,小心处理隐含可能是一个好主意。

如果它不必是100%Scala,也可以是类似的东西,那么您可以试试Kotlin

- 奥利弗

答案 7 :(得分:2)

我确信这会被低估,但极快的周转并不总是有利于提高质量或生产力。

花时间仔细思考并执行更少的开发微周期。良好的Scala代码更密集,更重要(即没有偶然的细节和复杂性)。它需要更多的思考,需要时间(至少在开始时)。您可以通过更少的代码/测试/调试周期进行良好的进展,这些周期会更长一点,并且仍然可以提高您的工作效率和工作质量。

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