Вещи ускоряются, но это не имеет ничего общего с параллельным или последовательным, вы не сравниваете яблоки с яблоками. В JVM есть JIT (как раз вовремя) компилятор, который скомпилирует некоторый байт-код только после того, как код будет использован определенное количество раз. Итак, что вы видите в первых итерациях, это медленное выполнение кода, который еще не является JIT, а также время для самой продолжающейся JIT-компиляции. Удаление .par
так, чтобы оно было последовательным , вот что я вижу на своей машине (итерация в 10 раз меньше, потому что я использую более старую машину):
Sequential (ms): 312
Iteration[1] Executed in 117 ms
Iteration[2] Executed in 112 ms
Iteration[3] Executed in 112 ms
Iteration[4] Executed in 112 ms
Iteration[5] Executed in 114 ms
Iteration[6] Executed in 113 ms
Iteration[7] Executed in 113 ms
Iteration[8] Executed in 117 ms
Iteration[9] Executed in 113 ms
Iteration[10] Executed in 111 ms
Но это все последовательно! Вы можете увидеть, что JVM делает с точки зрения JIT, используя JVM -XX:+PrintCompilation
(установите в JAVA_OPTS
или используйте опцию -J-XX:+PrintCompilation
scala. На первых итерациях вы увидите большое количество операторов печати JVM, показывающих, что такое JIT затем стабилизируется.
Итак, чтобы сравнить яблоки с яблоками, вы сначала запускаете без пар, затем добавляете пар и запускаете ту же программу. На моем двухъядерном процессоре при использовании .par
получаю:
Sequential (ms): 329
Iteration[1] Executed in 197 ms
Iteration[2] Executed in 60 ms
Iteration[3] Executed in 57 ms
Iteration[4] Executed in 58 ms
Iteration[5] Executed in 59 ms
Iteration[6] Executed in 73 ms
Iteration[7] Executed in 56 ms
Iteration[8] Executed in 60 ms
Iteration[9] Executed in 58 ms
Iteration[10] Executed in 57 ms
Так что примерно в два раза ускорение, когда оно станет стабильным.
В связанной заметке другая вещь, с которой вы должны быть осторожны, это бокс и распаковка, особенно если вы сравниваете только с Java. Функции высокого порядка в библиотеке scala, такие как filter, выполняют упаковку и распаковку примитивных типов, и это обычно является источником первоначального разочарования для тех, кто конвертирует код из Java в Scala.
Хотя это и не применяется в этом случае, поскольку for
выходит за пределы времени, есть также некоторые затраты на использование for
вместо while
, но компилятор 2.9.1 должен делать достойную работу, когда используя -optimize
скалярный флаг.