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

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

Рекурсия хвоста может повлиять на

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

или

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

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

Ответы

Ответ 1

Не ваши примеры будут быстрее, потому что, если вы используете 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/