Почему clojure работает хуже, чем scala в тестах alioth - PullRequest
11 голосов
/ 10 ноября 2010

См. http://shootout.alioth.debian.org/u32q/compare.php?lang=clojure Clojure намного медленнее, чем java-сервер, тогда как scala - нет.

Что дает?

ref: О производительности и совместимости Java: Clojure vs. Scala

Ответы [ 6 ]

11 голосов
/ 11 ноября 2010

Вы можете написать быстрый или медленный код на любом языке: -)

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

Например, следующие функции в Clojure очень крутые и полезные для удобства разработки, но приводят к некоторому снижению производительности во время выполнения:

  • Ленивые последовательности и списки
  • Динамическая совместимость Java с использованием отражения
  • Композиция функций времени выполнения / функции первого класса
  • Мультиметоды / динамическая отправка
  • Динамическая компиляция с eval или на REPL
  • BigInteger арифметика

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

  • Статический тип хинтинга (чтобы избежать отражения)
  • 1026 * Переходные *
  • Макросы (для манипулирования кодом времени компиляции)
  • Протоколы
  • Java-примитивы и массивы
  • цикл / повтор для итерации

При разумном использовании вышесказанного я обнаружил, что, как правило, в Clojure 1.2+ можно очень близко приблизиться к производительности Java, например. рассмотрим следующий код, чтобы сделать миллион дополнений:

Неоптимизированное Clojure с использованием ленивой последовательности и арифметики бигинтергеров. Это красиво и функционально, но не очень быстро:

(reduce 
  (fn [acc val] (unchecked-int (unchecked-add (int acc) (int val)))) 
  (range 0 1000000))

=> "Elapsed time: 65.201243 msecs"

Оптимизированное Clojure с примитивной арифметикой и циклом / рекурсом:

(loop [acc (int 0) i (int 0)] 
  (if (>= i (int 1000000)) 
    acc 
    (recur (unchecked-add acc i) (unchecked-inc i)) ))

=> "Elapsed time: 0.691474 msecs"

Java код, довольно стандартный итерационный цикл:

public static int addMillion() {
    int result=0;
    for (int i=0; i<1000000; i++) {
        result+=i;
    }
    return result;
}

=> "Elapsed time: 0.692081 msecs"

p.s. Я использовал unchecked-add вместо + в коде Clojure, чтобы он соответствовал поведению целочисленного переполнения Java.

4 голосов
/ 10 ноября 2010

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

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

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

3 голосов
/ 11 ноября 2010

Частично это связано с самим тестом, а именно с тем, что вы должны написать свой код (на каком бы языке это ни было), чтобы выполнить точные те же шаги реализации, что и для версии Java. О, у вас есть другой, возможно более быстрый способ сделать X на вашем языке? Жаль.

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

2 голосов
/ 11 ноября 2010

Написание более быстрых версий выглядит забавно ...

1 голос
/ 10 ноября 2010

Многие тесты работают медленнее, потому что до самого недавнего времени потребовалось гораздо больше работы и экспертных знаний, чтобы добиться хорошей производительности от Clojure. Эти ориентиры ориентированы в основном на 1,2.

Clojure 1.3 имеет несколько улучшений, которые значительно упрощают написание исполняемого кода. Несмотря на это, не так много людей в сообществе знакомы с улучшением производительности кода Clojure - так что это будет постепенный процесс, так как люди представляют лучшие версии.

0 голосов
/ 10 ноября 2010

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

С другой стороны, Clojure был разработан с совершенно другим подходом к программированию и имеет функции длявзаимодействовать с Java.Однако несоответствие импеданса между обоими языками (а JVM подготовлена ​​для Java) может сделать Clojure немного медленнее.Для некоторых проблем Clojure может быть быстрее (например, с использованием неизменяемых коллекций), но, возможно, не для большинства приложений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...