Ответ 1
Вот этапы компилятора scala, а также слегка отредактированные версии их комментариев из исходного кода. Обратите внимание, что это компилятор необычен в том, что он сильно взвешен для проверки типа и к преобразованиям, которые больше похожи на десурагирование. Другие компиляторы включают много кода для: оптимизации, распределения регистров и перевод в ИК.
Некоторые точки верхнего уровня:Существует много переписывания деревьев. Каждая фаза имеет тенденцию читать в дереве от предыдущего этапа и преобразовать его в новое дерево. Символы, чтобы контрастность, остаются значимыми на протяжении всей жизни компилятора. Так деревья имеют указатели на символы, а не наоборот. Вместо переписывание символов, новая информация присоединяется к ним как фазы прогресс.
Вот список фаз из Global:
analyzer.namerFactory: SubComponent,
analyzer.typerFactory: SubComponent,
superAccessors, // add super accessors
pickler, // serializes symbol tables
refchecks, // perform reference and override checking,
translate nested objects
liftcode, // generate reified trees
uncurry, // uncurry, translate function values to anonymous
classes
tailCalls, // replace tail calls by jumps
explicitOuter, // replace C.this by explicit outer pointers,
eliminate pattern matching
erasure, // erase generic types to Java 1.4 types, add
interfaces for traits
lambdaLift, // move nested functions to top level
constructors, // move field definitions into constructors
flatten, // get rid of inner classes
mixer, // do mixin composition
cleanup, // some platform-specific cleanups
genicode, // generate portable intermediate code
inliner, // optimization: do inlining
inlineExceptionHandlers, // optimization: inline exception handlers
closureElimination, // optimization: get rid of uncalled closures
deadCode, // optimization: get rid of dead cpde
if (forMSIL) genMSIL else genJVM, // generate .class files
некоторая работа с компилятором scala
Таким образом, компилятор scala должен выполнять намного больше работы, чем компилятор Java, однако, в частности, есть некоторые вещи, которые делают компилятор scala значительно медленнее, включая
- Неявное разрешение. Неявное разрешение (т.е. Скаляр, пытающееся найти неявное значение при создании неявного объявления) пузырится над каждой родительской областью в объявлении, это время поиска может быть массивным (особенно если вы ссылаетесь на одну и ту же неявную переменную много раз, а ее объявленные в некоторой библиотеке вплоть до вашей последовательности зависимостей). Время компиляции становится еще хуже, когда вы принимаете во внимание неявное распознавание признаков и классы типов, которые в значительной степени используются библиотеками, такими как scalaz и бесформенными.
Также используется огромное количество анонимных классов (т.е. Lambdas, блоки, анонимные функции). Макросы, очевидно, добавляют к времени компиляции.
Очень приятная запись Мартина Одерского
Далее компиляторы Java и scala преобразуют исходный код в байт-код JVM и делают очень мало оптимизации. На большинстве современных JVM, как только запущен программный байт-код, он преобразуется в машинный код для компьютерной архитектуры, на которой он запустить. Это называется компиляцией "точно в срок". Однако уровень оптимизации кода, однако, невысок с компиляцией "точно вовремя", поскольку он должен быть быстрым. Чтобы избежать повторной компиляции, так называемый HotSpot компилятор только оптимизирует части кода, которые выполняются часто.
Программа может иметь разную производительность при каждом запуске. Выполнение одного и того же фрагмента кода (например, метода) несколько раз в одном экземпляре JVM может дать очень разные результаты производительности в зависимости от того, был ли оптимизирован конкретный код между прогонами. Кроме того, измерение времени выполнения некоторого фрагмента кода может включать в себя время, в течение которого сам компилятор JIT выполнял оптимизацию, что давало противоречивые результаты.
Одной из распространенных причин ухудшения производительности является также бокс и unboxing, которые происходят неявно при передаче примитивного типа в качестве аргумента в общий метод, а также частые GC.
Существует несколько подходов, чтобы избежать вышеупомянутых эффектов во время измерения, например It запускаться с использованием серверной версии JSM HotSpot, которая делает более агрессивную оптимизацию. Visualvm - отличный выбор для профилирования приложения JVM. Это визуальный инструмент, объединяющий несколько инструментов JDK командной строки и облегченные возможности профилирования. Однако абстракции scala очень сложны и, к сожалению, VisualVM еще не поддерживает this.parsing механизмы, которые занимали много времени, чтобы обрабатывать как причина, используя много
exists
иforall
, которые являются методами коллекций scala, которые принимают предикаты, предикаты к FOL и, таким образом, могут передавать полную последовательность, максимизирующую производительность.Кроме того, создание модулей cohisive и менее зависимым является жизнеспособным решением. Помните, что промежуточный код gen somtimes зависит от машины, и различные архитектурные заставки дают разнообразные результаты.
Альтернатива: Typesafe выпустил Zinc, который отделяет быстрый инкрементный компилятор от sbt и позволяет использовать maven/другие инструменты сборки. Таким образом, использование цинка с плагином scala maven сделало компиляцию намного быстрее.
Простая задача: учитывая список целых чисел, удалите самый большой. Заказ не требуется.
Ниже приведена версия решения (в среднем, я думаю).
def removeMaxCool(xs: List[Int]) = {
val maxIndex = xs.indexOf(xs.max);
xs.take(maxIndex) ::: xs.drop(maxIndex+1)
}
Он scala идиоматический, сжатый и использует несколько хороших функций списка. Это также очень неэффективно. Он перемещается по списку как минимум 3 или 4 раза.
Теперь рассмотрим это Java-подобное решение. Это также будет писать разумный разработчик Java (или scala новичок).
def removeMaxFast(xs: List[Int]) = {
var res = ArrayBuffer[Int]()
var max = xs.head
var first = true;
for (x <- xs) {
if (first) {
first = false;
} else {
if (x > max) {
res.append(max)
max = x
} else {
res.append(x)
}
}
}
res.toList
}
Полностью не-w610 > идиоматический, нефункциональный, нечеткий, но очень эффективный. Он перемещает список только один раз!
Таким образом, компромиссы также должны быть приоритетными, и иногда вам, возможно, придется работать над такими вещами, как разработчик java, если нет.