Улучшения Clojure JVM 7/8 - PullRequest
       25

Улучшения Clojure JVM 7/8

14 голосов
/ 29 ноября 2010

Рич Хикки и другие отметили, что Clojure не получит значительного улучшения от запланированного invokeDynamic, запланированного для JVM 7 или 8, но увидит прирост производительности от хвостовой рекурсии.

Будет ли хвостовая рекурсия иметьлюбой эффект на

(fn [...] (recur ...))

или

(loop [...] (recur ...))

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

1 Ответ

17 голосов
/ 29 ноября 2010

Ваши примеры будут работать быстрее, потому что, если вы используете recur, вы уже сообщаете компилятору, что у вас есть хвостовая рекурсивная функция, и это позволяет компилятору генерировать байт-код, который использует goto (как обычный императивный цикл)

Конечно, есть некоторые преимущества, если JVM оптимизирует хвостовой вызов.

Вам больше не придется использовать recur (если вы не хотите), чтобы вы могли написать такую ​​функцию (хвостовая рекурсивная функция)

(defn testfn [n] (when (not= 1000 n) (testfn n)))

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

(defn testfn [n] (when (not= 1000 n) (recur n)))

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

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

(defn even [n] (if (zero? n) true (odd? (dec n)))
(defn odd  [n] (if (zero? n) false (even (dec n)))

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

У меня осталось небольшое дополнение. Есть функция под названием trampoline, которая позволяет вам уже делать это (с небольшим изменением стиля программирования и некоторыми накладными расходами) Вместо объяснения trampoline я отошлю вас к блогу, который делает именно это:

http://pramode.net/clojure/2010/05/08/clojure-trampoline/

...