为什么对此Scala代码进行小的更改会对性能产生如此大的影响? [英] Why does a small change to this Scala code make such a huge difference to performance?

查看:68
本文介绍了为什么对此Scala代码进行小的更改会对性能产生如此大的影响?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在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代码进行小的更改会对性能产生如此大的影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆