问题描述
我正在32位 Debian 6.0 (压缩)系统上运行( 2.5 GHz的 Core 2 CPU),sun-java6 6.24-1,但使用Wheezy的Scala 2.8.1软件包
使用scalac -optimise
编译的这段代码需要30秒钟才能运行:
object Performance {
import scala.annotation.tailrec
@tailrec def gcd(x:Int,y:Int):Int = {
if (x == 0)
y
else
gcd(y%x,x)
}
val p = 1009
val q = 3643
val t = (p-1)*(q-1)
val es = (2 until t).filter(gcd(_,t) == 1)
def main(args:Array[String]) {
println(es.length)
}
}
但是,如果我做了微不足道的更改,将val es=
向下移动了一行并在main
的范围内,那么它只需要1秒的时间,这更像是我期望看到的,并且与等效C ++的性能.有趣的是,将val es=
保留在原位置但用lazy
进行限定也具有相同的加速效果.
这是怎么回事?为什么在功能范围之外执行计算如此之慢?
JVM不会将静态初始化程序(这就是它)优化到与优化方法调用相同的级别.不幸的是,当您在那里做大量工作时,这会损害性能-这是一个完美的例子.这也是为什么旧的Application
特性被认为是有问题的原因,也是为什么在Scala 2.9中有一个DelayedInit
特性可以得到一些编译器帮助,以便将内容从初始化程序移入稍后调用的方法. /p>
(将构造函数"固定为初始化程序".相当长的错字!)
I'm running on a 32-bit Debian 6.0 (Squeeze) system (a 2.5 GHz Core 2 CPU), sun-java6 6.24-1 but with the Scala 2.8.1 packages from Wheezy.
This code, compiled with scalac -optimise
, takes over 30 seconds to run:
object Performance {
import scala.annotation.tailrec
@tailrec def gcd(x:Int,y:Int):Int = {
if (x == 0)
y
else
gcd(y%x,x)
}
val p = 1009
val q = 3643
val t = (p-1)*(q-1)
val es = (2 until t).filter(gcd(_,t) == 1)
def main(args:Array[String]) {
println(es.length)
}
}
But if I make the trivial change of moving the val es=
one line down and inside the scope of main
, then it runs in just 1 second, which is much more like I was expecting to see and comparable with the performance of equivalent C++. Interestingly, leaving the val es=
where it is but qualifying it with lazy
also has the same accelerating effect.
What's going on here? Why is performing the calculation outside function scope so much slower?
The JVM doesn't optimize static initializers (which is what this is) to the same level that it optimizes method calls. Unfortunately, when you do a lot of work there, that hurts performance--this is a perfect example of that. This is also one reason why the old Application
trait was considered problematic, and why there is in Scala 2.9 a DelayedInit
trait that gets a bit of compiler help to move stuff from the initializer into a method that's called later on.
(Edit: fixed "constructor" to "initializer". Rather lengthy typo!)
这篇关于为什么对此Scala代码进行小的更改会对性能产生如此大的影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!