scala vs java, производительность и память? [закрытый]



Я очень хочу заглянуть в Scala, и у меня есть один основной вопрос, на который я не могу найти ответ:
в общем, есть ли разница в производительности и использовании памяти между Scala и Java?

696   8  

8 ответов:

Scala позволяет очень легко использовать огромные объемы памяти, не осознавая этого. Это, как правило, очень мощный, но иногда может раздражать. Например, предположим, что у вас есть массив строк (называемых array), и карта из этих строк в файлы (называется mapping). Предположим, вы хотите получить все файлы, которые находятся на карте и исходят из строк длиной больше двух. В Java, вы можете

int n = 0;
for (String s: array) {
  if (s.length > 2 && mapping.containsKey(s)) n++;
}
String[] bigEnough = new String[n];
n = 0;
for (String s: array) {
  if (s.length <= 2) continue;
  bigEnough[n++] = map.get(s);
}

уфф! Тяжелая работа. В Scala, самый компактный способ сделать то же самое:

val bigEnough = array.filter(_.length > 2).flatMap(mapping.get)

легко! Но, если вы не знакомы с тем, как работают коллекции, вы можете не понимать, что этот способ создания этого дополнительного промежуточного массива (с filter), и дополнительный объект для каждый элемент массиваmapping.get, которая возвращает параметр). Он также создает два объекта функции (один для фильтра и один для flatMap), хотя это редко является серьезной проблемой, так как объекты функции маленький.

таким образом, в основном, использование памяти, на примитивном уровне, то же самое. Но библиотеки Scala имеют много мощных методов, которые позволяют создавать огромное количество (обычно недолговечных) объектов очень легко. Сборщик мусора обычно довольно хорош с таким мусором, но если вы полностью забываете о том, какая память используется, вы, вероятно, столкнетесь с проблемами раньше в Scala, чем в Java.

обратите внимание, что компьютерные языки бенчмарк игры Scala код написан в довольно Java-подобном стиле, чтобы получить Java-подобную производительность, и, таким образом, имеет Java-подобное использование памяти. Вы можете сделать это в Scala: если вы пишете свой код, чтобы выглядеть как высокопроизводительный код Java, это будет высокопроизводительный код Scala. (Ты мая быть в состоянии написать его в более идиоматическом стиле Scala и по-прежнему получить хорошую производительность, но это зависит от специфики.)

Я должен добавить, что за количество времени, потраченного на Программирование, мой код Scala обычно быстрее чем мой Java-код, так как в Scala я могу получить утомительные не-критические части, выполненные с меньшими усилиями, и потратить больше моего внимания на оптимизацию алгоритмов и кода для критических частей производительности.

Я новый пользователь, поэтому я не могу добавить комментарий к ответу Рекса Керра выше (позволяя новым пользователям "отвечать", но не "комментировать" - очень странное правило кстати).

Я подписался просто, чтобы ответить на "фу, Java настолько многословна и такая тяжелая работа" намек на популярный ответ Рекса выше. Хотя вы, конечно, можете написать более сжатый код Scala, приведенный пример Java явно раздут. Большинство разработчиков Java-код будет что-то вроде этого:

List<String> bigEnough = new ArrayList<String>();
for(String s : array) {
  if(s.length() > 2 && mapping.get(s) != null) {
    bigEnough.add(mapping.get(s));
  }
}

и конечно, если мы собираемся притвориться, что Eclipse не делает большую часть фактического ввода для вас и что каждый сохраненный символ действительно делает вас лучшим программистом, то вы можете закодировать это:

List b=new ArrayList();
for(String s:array)
  if(s.length()>2 && mapping.get(s) != null) b.add(mapping.get(s));

напишите свой Scala, как Java, и вы можете ожидать, что будет выпущен почти идентичный байт - код-с почти идентичными метриками.

напишите его более "идиоматично", с неизменяемыми объектами и функциями более высокого порядка, и он будет немного медленнее и немного больше. Единственным исключением из этого эмпирического правила является использование универсальных объектов, в которых параметры типа используют @specialised аннотация, это создаст еще больший байт-код, который может опережать производительность Java, избегая бокс/распаковка.

также стоит упомянуть тот факт, что больше памяти / меньше скорости является неизбежным компромиссом при написании кода, который может выполняться параллельно. Идиоматический код Scala является гораздо более декларативным по своей природе, чем типичный код Java, и часто составляет всего 4 символа (.par) от того, чтобы быть полностью параллельным.

Если

  • код Scala занимает 1.25 x больше, чем код Java в одном потоке
  • может быть легко разделить на 4 ядра (сейчас даже в ноутбуках)
  • для параллельного времени выполнения (1.24 / 4 =) 0.3125 x оригинальная Java

вы бы тогда сказали, что код Scala теперь сравнительно на 25% медленнее или в 3 раза быстрее?

правильный ответ зависит от того, как именно вы определяете "эффективность" :)

Компьютерный Язык Бенчмарки Игры:

тест скорости java / scala 1.71 / 2.25

тест памяти java / scala 66.55 / 80.81

Итак, эти тесты говорят, что java на 24% быстрее, а scala использует на 21% больше памяти.

All-in-all это не имеет большого значения и не должно иметь значения в реальных приложениях, где большая часть времени потребляется базой данных и сетью.

итог: если Scala делает вас и ваш команда (и люди, принимающие проект, когда вы уходите) более продуктивна, тогда вы должны пойти на это.

другие ответили на этот вопрос относительно узких петель, хотя, похоже, существует очевидная разница в производительности между примерами Рекса Керра, которые я прокомментировал.

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

я относительно новичок в Scala (около года или около того), но ощущение его, до сих пор, заключается в том, что он позволяет вам отложить многие аспекты дизайна, реализация и выполнение относительно легко (с достаточным фоновым чтением и экспериментами:)

Отложенные Конструктивные Особенности:

Отложенная Реализация Особенности:

Отложенное Выполнение Функции: (извините, без ссылок)

  • Потокобезопасные ленивые значения
  • Pass-by-name
  • Монадическом вещи

эти особенности, для меня, это те, которые помогают нам идти по пути к быстрым, плотным применениям.


примеры Рекса Керра отличаются тем, какие аспекты исполнения откладываются. В примере Java выделение памяти откладывается до тех пор, пока не будет вычислен ее размер, где пример Scala откладывает поиск сопоставления. Мне они кажутся совершенно разными алгоритмами.

вот что я думаю, это больше яблоки к яблокам эквивалент для его примера Java:

val bigEnough = array.collect({
    case k: String if k.length > 2 && mapping.contains(k) => mapping(k)
})

нет промежуточных коллекций, нет Option экземпляров и т. д. Это также сохраняет тип коллекции, так bigEnoughС типом Array[File] -Array ' s collect реализация, вероятно, будет делать что-то вроде того, что делает Java-код г-на Керра.

отложенные функции проектирования, перечисленные выше, также позволят разработчикам API коллекции Scala реализовать эту быструю реализацию сбора данных для конкретных массивов в будущих выпусках, не нарушая API. Это то, что я имею в виду, когда иду по пути скорость.

также:

val bigEnough = array.withFilter(_.length > 2).flatMap(mapping.get)

The withFilter метод, который я использовал здесь вместо filter Исправлена проблема промежуточной коллекции, но все еще есть проблема экземпляра опции.


одним из примеров простой скорости выполнения в Scala является ведение журнала.

в Java мы могли бы написать что-то вроде:

if (logger.isDebugEnabled())
    logger.debug("trace");

в Scala, это просто:

logger.debug("trace")

потому что параметр сообщения для отладки в Scala имеет типа "=> String " который я рассматриваю как функцию без параметров, которая выполняется при ее оценке, но которая в документации вызывает pass-by-name.

изменить { Функции в Scala-это объекты, поэтому здесь есть дополнительный объект. Для моей работы вес тривиального объекта стоит удалить возможность ненужной оценки сообщения журнала. }

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

для меня это последовательная тема в Scala.


жесткий код не может захватить, почему Scala быстрее, хотя он немного намекает.

я чувствую, что это комбинация повторного использования кода и потолка качества кода в Scala.

в Java удивительный код часто вынужден становиться непонятным беспорядком и поэтому не является действительно жизнеспособным в рамках качества производства API, поскольку большинство программистов не смогут его использовать.

я очень надеюсь, что Scala может позволить эйнштейнам среди нас реализовать гораздо более компетентные API, потенциально выраженные через DSLs. Основные API на Scala уже далеко продвинулись по этому пути.

Java и Scala оба компилируются до байт-кода JVM, поэтому разница не так велика. Лучшее сравнение вы можете получить, вероятно, на компьютерный язык контрольные игры, что по существу говорит о том, что Java и Scala имеют одинаковое использование памяти. Скала-это только немного медленнее, чем Java на некоторых из перечисленных тестов, но это может быть просто потому, что реализация программ отличаются.

на самом деле, они оба так близко об этом не стоит беспокоиться. Увеличение производительности, которое вы получаете, используя более выразительный язык, такой как Scala, стоит намного больше, чем минимальный (если таковой имеется) хит производительности.

@higherkindeds презентация на эту тему - Соображения Производительности Scala что делает некоторые сравнения Java/Scala.

инструменты:

большой блогпост:

пример Java действительно не является идиомой для типичных прикладных программ. Такой оптимизированный код можно найти в методе системной библиотеки. Но тогда он будет использовать массив правильного типа, т. е. File[] и не будет бросать IndexOutOfBoundsException. (Различные условия фильтра для подсчета и добавления). Моя версия была бы (всегда (!) с фигурными скобками, потому что мне не нравится тратить час на поиск ошибки, которая была введена путем сохранения 2 секунд, чтобы нажать одну клавишу Затмение):

List<File> bigEnough = new ArrayList<File>();
for(String s : array) {
  if(s.length() > 2) {
    File file = mapping.get(s);
    if (file != null) {
      bigEnough.add(file);
    }
  }
}

но я мог бы принести вам много других уродливых примеров кода Java из моего текущего проекта. Я пытался избежать общего копирования и изменения стиля кодирования путем факторинга общих структур и поведения.

в моем абстрактном базовом классе DAO у меня есть абстрактный внутренний класс для общего механизма кэширования. Для каждого конкретного типа объекта модели существует подкласс абстрактного базового класса DAO, в котором внутренний класс является подклассом для обеспечения реализации для метода, который создает бизнес-объект при его загрузке из базы данных. (Мы не можем использовать инструмент ORM, потому что мы получаем доступ к другой системе через собственный API.)

этот код подкласса и экземпляра не совсем понятен в Java и был бы очень читаемым в Scala.

Comments

    Ничего не найдено.