Rich Hickey和其他人已經提到,Clojure不會從即將到來的invokeDynamic
計劃爲JVM 7或8獲得顯着改進,但會從尾遞歸中看到性能增益。Clojure JVM 7/8改進
威爾尾遞歸有
(fn [...] (recur ...))
或
(loop [...] (recur ...))
任何影響,我不希望他們得到任何更快,因爲編譯器可能已經產生循環結構。
Rich Hickey和其他人已經提到,Clojure不會從即將到來的invokeDynamic
計劃爲JVM 7或8獲得顯着改進,但會從尾遞歸中看到性能增益。Clojure JVM 7/8改進
威爾尾遞歸有
(fn [...] (recur ...))
或
(loop [...] (recur ...))
任何影響,我不希望他們得到任何更快,因爲編譯器可能已經產生循環結構。
非你的例子會得到更快了,因爲如果你使用recur
你已經告訴你有一個尾遞歸函數的編譯器,這允許編譯器生成使用goto
(像一個正常的必要的循環)字節碼
如果JVM獲得尾部呼叫優化,那麼有一些好處。
你不會有使用復發了(如果你不想),所以你可以寫這樣的功能(一尾遞歸函數)
(defn testfn [n] (when (not= 1000 n) (testfn n)))
Nowdays的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
的功能我將把你所做的正是這一個博客: