Почему небольшие изменения в этом Scala-коде так сильно влияют на производительность?

Я использую 32-разрядную систему Debian 6.0 (Squeeze) (процессор Core 2 с частотой 2,5 ГГц), sun-java6 6.24-1, но с пакетами Scala 2.8.1 от Wheezy.

Этот код, скомпилированный с 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 также имеет такой же ускоряющий эффект.

Что тут происходит? Почему выполнение вычислений вне области функций происходит намного медленнее?

2 ответа

Решение

JVM не оптимизирует статические инициализаторы (что и есть) до того же уровня, что оптимизирует вызовы методов. К сожалению, когда вы там много работаете, это ухудшает производительность - это прекрасный пример этого. Это также одна из причин, почему старый Application черта была признана проблемной, и почему в Scala 2.9 есть DelayedInit черта, которая получает немного компилятора, помогает перемещать вещи из инициализатора в метод, который вызывается позже.


(Правка: исправлен "конструктор" в "инициализаторе". Довольно длинная опечатка!)

Код внутри блока объекта верхнего уровня транслируется в статический инициализатор класса объекта. Эквивалент в Java будет

class Performance{
    static{
      //expensive calculation
    }
    public static void main(String[] args){
      //use result of expensive calculation
    }
}

HotSpot JVM не выполняет никаких оптимизаций для кода, встречающегося во время статических инициализаторов, при разумной эвристике, что такой код будет запущен только один раз.

Другие вопросы по тегам