2010-11-29 16 views
14

Rich Hickey和其他人已經提到,Clojure不會從即將到來的invokeDynamic計劃爲JVM 7或8獲得顯着改進,但會從尾遞歸中看到性能增益。Clojure JVM 7/8改進

威爾尾遞歸有

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

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

任何影響,我不希望他們得到任何更快,因爲編譯器可能已經產生循環結構。

回答

17

非你的例子會得到更快了,因爲如果你使用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的功能我將把你所做的正是這一個博客:

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