Scala perf: Почему это приложение Scala в 30 раз медленнее, чем эквивалентное Java-приложение?
Я очень опытный разработчик С#, но мне нужно начать писать код, который работает на JVM. Язык Java отличается от С# в наши дни, поэтому меня интересовали функции, предлагаемые Scala.
Однако, слушая, что в Scala все операторы - это просто методы, я стал подозревать влияние производительности, которое будет иметь на вычисления с математическим вычислением (что важно для типов приложений, которые пишет моя команда)
Итак, я провел несколько простых тестов на основе int и обнаружил, что Scala примерно на 30 раз медленнее, чем эквивалентный Java-код. Нехорошо! Может ли кто-нибудь сказать мне, что я делаю неправильно? или как улучшить вычислительную производительность примера Scala, чтобы быть наравне с Java?
UPDATE1: как указывалось в первых двух ответах, я был супер-нубом и выполнял его в IntelliJ IDE. Я не знаю, как запустить приложение Scala через командную строку java, что может быть проблемой IntelliJ. Спасибо за помощь ребятам, мне нужно исследовать простое выполнение командной строки Scala, прежде чем продолжить с перфекционистского тестирования, так как результаты IDE, очевидно, слишком неточны.
UPDATE2: Луиджи в комментариях говорит, что в IntelliJ он получает равные времена, поэтому кажется, что моя дикая разница не связана с IntelliJ? Любые другие идеи о том, что это может быть? Я попробую запустить это через командную строку и опубликовать обновление с моими результатами.
Update3:
после запуска этого через командную строку я получаю ту же самую 30-кратную разницу.
Мой компьютер 3core AMD x64 3.4Ghz, работает J2SE 6 jdk 64bit 1.6.0_31, Window7.
Вот мои временные ряды:
Java: 210ms.
Scala: между 2000 и 7400 мс (обычно диапазон 7000)
поэтому, я думаю, вопрос все еще открыт. почему Scala работает так медленно на моей платформе? что-то с java 64-битной версией или с Java 6?
версии исполнения:
C:\Users\jason>java -showversion
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)
C:\Users\jason>scala
Welcome to Scala version 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_31).
UPDATE 4, в то время как мой первоначальный тест имеет разницу в 30 раз, увеличение итераций до 100000000 приводит к уменьшению разницы до примерно 33%, поэтому кажется, что Scala все еще доминирует в некоторых неизвестных затратах на инициализацию на моей машине. Я закрою это с наивысшим рейтингом, потому что я не думаю, что мы узнаем о проблеме производительности, потому что никто, кроме меня, не видит проблему: (
* ОБНОВЛЕНИЕ 5, РЕШЕНИЕ: на основе справки из 2 ответов, которые я получил, я понял проблему, см. мой ответ ниже для более подробной информации (резюме: первый вызов System.nanoTime() принимает долгое время) *
Вот мои примеры приложений:
//scala
object HelloWorld {
//extends Application {
def main(args: Array[String]) {
println("hello scala")
var total: Long = 0
var i: Long = 0
var x: Long=0;
//warm up of the JVM to avoid timing of runtime initialization
while (i < 100000)
{
x=i;
x += x - 1;
x -= x + 1;
x += 1;
x -= 1;
total += x;
i+=1;
}
//reset variables
total = 0
i = 0;
//start timing
var start: Long = System.nanoTime
//run test
while (i < 100000) {
x=i;
x += x - 1;
x -= x + 1;
x += 1;
x -= 1;
total += x;
i+=1;
}
var end: Long = System.nanoTime
System.out.println("ms, checksum = ")
System.out.println((end - start) / 1000)
System.out.println(total)
}
}
а вот эквивалент java, на 30 раз быстрее
//java
public class app {
public static void main(String[] args)
{
String message = "hello, java";
System.out.println(message);
long total = 0;
//warm up of the JVM to avoid timing of runtime initialization
for(long i=0;i< 100000;i++)
{
long x=i;
x+=x-1;
x-=x+1;
x++;
x--;
total+=x;
}
//reset variables
total = 0;
//start timing and run test
long start = System.nanoTime();
for(long i=0;i< 100000;i++)
{
long x=i;
x+=x-1;
x-=x+1;
x++;
x--;
total+=x;
}
long end = System.nanoTime();
System.out.println("ms, checksum = ");
System.out.println((end-start)/1000);
System.out.println(total);
}
}
Ответы
Ответ 1
Итак, я предполагаю, что сам понял ответ.
Проблема заключается в вызове System.nanoTime
. Для этого требуется некоторая стоимость инициализации (загрузка базовых библиотек Java и т.д.), Что гораздо дешевле загружать при вызове из среды выполнения Java, чем из среды выполнения Scala.
Я доказываю это, изменяя начальное значение total, вместо этого устанавливая его на
var total: Long = System.nanoTime()
Это добавляется до первого цикла "разогрева", и теперь это делает обе версии приложения (Java и Scala) одновременно: около 2100 для 1000000 итераций.
Спасибо за помощь ваших ребят за это, я бы не подумал об этом без вашей помощи.
ps: Я оставлю "принятый ответ" как есть, потому что я бы не проследил это без его помощи.
Ответ 2
Я заново запустил ваш код (и увеличил количество циклов x1000, чтобы получить некоторое значение в эталоне).
Результаты:
Scala: 92 ms
Java: 59 ms
Вы можете видеть, что Java на 30% быстрее.
Глядя на байт-код, я могу сказать, что две версии почти идентичны - так что разница действительно странная (список байткодов довольно длинный, поэтому я не буду публиковать его здесь).
Увеличение счета x10000 дает следующее:
Scala: 884 ms
Java: 588 ms
Поскольку результаты довольно стабильны, где-то должен быть какой-то постоянный фактор. Может быть, в некоторых параметрах, которые бегун "scala" переходит к JVM?
EDIT:
Моя конфигурация:
$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)
$ scala -version
Scala code runner version 2.9.0.1 -- Copyright 2002-2011, LAMP/EPFL
$ inxi -SCD
System: Host the-big-maker Kernel 2.6.35-22-generic x86_64 (64 bit) Distro Linux Mint 10 Julia
CPU: Quad core AMD Phenom II X4 965 (-MCP-) cache 2048 KB flags (lm nx sse sse2 sse3 sse4a svm)
Clock Speeds: (1) 800.00 MHz (2) 800.00 MHz (3) 800.00 MHz (4) 800.00 MHz
Disks: HDD Total Size: 750.2GB (5.8% used) 1: /dev/sda OCZ 90.0GB
2: /dev/sdb ST3500413AS 500.1GB 3: /dev/sdc ST3802110A 80.0GB
4: /dev/sdd Maxtor_6Y080M0 80.0GB
Ответ 3
$ javac app.java
$ scalac app.scala
$ scala HelloWorld
hello scala
ms, checksum =
1051
-100000
$ java app
hello, java
ms, checksum =
1044
-100000
Что я делаю неправильно?