Java编译速度与Scala编译速度


101

我已经在Scala中编程了一段时间了,我喜欢它,但是令我烦恼的是编译程序所花费的时间。这似乎是一件小事,但是使用Java我可以对程序进行一些小的更改,单击netbeans中的运行按钮,然后BOOM就会运行,随着时间的推移,在scala中进行编译似乎会花费大量时间。我听说在许多大型项目中,脚本编写语言变得非常重要,因为需要花费大量的编译时间,而使用Java时却没有看到这种需求。

但是我来自Java,据我了解,它比任何其他编译语言都快,并且由于我改用Scala的原因而变得更快(这是一种非常简单的语言)。

所以我想问一下,我可以使Scala编译速度更快,并且scalac会和javac一样快。


似乎有些用户同意您的意见;)twitter.com/etorreborre/status/21286172202
VonC 2010年

Go的编译速度比Java快。速度更快,这是在说些什么。
Daniel C. Sobral

啊哈哈,在我的情况下,平均scalac编译需要几分钟的时间,LOC很少,fsc稍微快一点。
Jeriho

Answers:


57

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

也就是说,从Scala 2.7到Scala 2.8,编译时间已经得到显着改善,并且由于尘埃落在2.8上,我希望这种改进将继续。此页面记录了一些正在进行的努力和想法,以提高Scala编译器的性能。

马丁·奥德斯基(Martin Odersky)在回答中提供了更多细节。



我已经从netbeans切换到ant + jedit(我知道,蚂蚁是给穴居人使用的,但是我会根据自己的时间发展),以便可以使用fsc。但是我想知道,Clojure的编译速度与Scala相比如何?它似乎具有Scala的许多功能,但我认为语法更容易解析。
user405163

1
我们在这里有点离题了,但是Clojure的编译器速度非常快(比等效源上的javac快得多)。没错,虽然它是一种非常简单的语言,但是它没有任何静态类型系统,这很有帮助。
丹尼尔·史派瓦克

458

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

  1. 更大的启动开销

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

    • 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
关于由于类加载而导致的启动开销:使用GCJ或Mono提前编译为本地代码会有所帮助吗?
机械蜗牛

15
如果用C ++重写Scala怎么办?:o)
marcus

使用invokedynamic字节码指令会有好处吗?
罗布·格兰特

40

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

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

3
@obox_lakes,讨厌nitpick,但是Java 确实需要对参数化方法进行类型推断int a<T>(T a) {},然后进行a(pls_infer_my_type)james-iry.blogspot.com/2009/04/...
埃拉扎尔Leibovich

13
@Elazar-是的,我知道。但是,坦白地说,在scala旁边称之为“类型推断”是可笑的!
oxbow_lakes


19

做Scala的最好方法是使用IDEA和SBT。设置一个基本的SBT项目(如果您愿意,它将为您完成)并在自动编译模式下运行它(命令~compile),然后在保存项目时SBT将对其进行重新编译。

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

无论哪种方式(外部运行SBT或SBT插件),SBT都将保持运行状态,因此“预热”了JIT版本的所有用于构建项目的类,并消除了启动开销。此外,SBT仅编译需要它的源文件。到目前为止,这是构建Scala程序的最有效方法。


9

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

有关更多信息,请参见“ 什么是最好的Scala构建系统? ”。


另一个解决方案是将fsc(用于Scala 2语言的快速脱机编译器)集成(如本博客文章中所示)作为IDE中的构建器。

替代文字

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

您不应直接在Eclipse中使用FSC,仅是因为Eclipse已在表面下使用FSC。
FSC基本上是驻留编译器之上的薄层,这正是Eclipse用来编译Scala项目的机制。


最后,正如杰克逊·戴维斯Jackson Davis)在评论中提醒我的那样:

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


2
sbt也可以进行增量编译
Jackson Davis 2010年

@杰克逊:触发执行,对!我已将其包含在我的答案中。
VonC

2
您不应直接在Eclipse中使用FSC,仅是因为Eclipse 在表面下使用FSC。FSC基本上是驻留编译器之上的薄层,这正是 Eclipse用来编译Scala项目的机制。
丹尼尔·史派瓦克

1
FSC代表Fast Scala编译器-而非Fast Java编译器
Ben McCann 2012年

@BenMcCann:糟糕。对。我已经确定了答案。
VonC 2012年

6

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

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


1
IntelliJ IDEA Scala插件还提供了使用fsc的选项
Aaron Novstrup 2010年

1
@anovstrup:是的,但是有时会崩溃。
丹尼斯·图斯基

4

您可以使用对Scala免费的JRebel插件。因此,您可以进行“在调试器中开发”,并且JRebel始终会在现场重新加载已更改的类。

我在Martin Odersky本人的某个地方读了一些声明,他说的是隐式搜索(编译器必须确保同一转换不超过一个隐式,以排除歧义)可以使编译器忙。因此,谨慎处理隐式可能是一个好主意。

如果不一定是100%Scala,也不一定是100%Scala,则可以尝试一下Kotlin

-奥利弗(Oliver)


2

我敢肯定这会被否决,但是快速的周转并不总是有利于质量或生产率。

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

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


3
我同意快速的周转周期不是必需的。但这没有伤害,对吗?
Elazar Leibovich 2010年

27
我不会拒绝投票,而是说您应该根据工具的限制(编译器的速度较慢)调整工作模式,而不是尝试改进工具,这并不是一个好主意。尤其是进行快速测试周期的能力非常有价值(即使它不能代替进行深入思考的需求,这种思考最好最好在键盘之外完成,但确实可以很好地加以补充)。
Thilo

9
我认为我的大部分生产力实际上都因为跑步前的思考而丧失了。我经常发现自己长时间在寻找一些方程式,试图发现潜在的陷阱正在等着我,而我一直在思考:“只要运行它!” 在我的脑后。可以肯定的是,当我运行该程序时,我学到的东西比经过一两个小时的冥想可能学到的东西要多得多。冥想很好,但是我觉得使用java进行增量编译/冥想的效果非常好。
user405163

2
这也类似于暗示莎士比亚不应该使用拼写检查器,而应该更认真地思考他想说的话。自动拼写检查器可以帮助您解决完全不同的问题。
Thilo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.