2013-05-14 48 views
8

我有一個ClojureScript程序,主要對集合進行數學計算。它是在慣用的,主機獨立的Clojure中開發的,所以很容易對它進行基準測試。令我驚訝的是(與Which is faster, Clojure or ClojureScript (and why)?的答案相反),ClojureScript中的相同代碼的運行速度比Clojure等效的要慢5-10倍。提高ClojureScript程序的性能

這是我做的。我打開了一個lein repl和一個瀏覽器代碼http://clojurescript.net/。然後我在這兩個REPL中嘗試了這些片段。

(time (dotimes [x 1000000] (+ 2 8))) 

(let [coll (list 1 2 3)] (time (dotimes [x 1000000] (first coll)))) 

然後我在瀏覽器REPL打開一個JavaScript控制檯,並寫了一個簡約的基準功能,

function benchmark(count, fun) { 
    var t0 = new Date(); 
    for (i = 0; i < count; i++) { 
    fun(); 
    } 
    var t1 = new Date(); 
    return t1.getTime() - t0.getTime(); 
} 

回到瀏覽器REPL:

(defn multiply [] (* 42 1.2)) 

然後嘗試兩個本地JavaScript乘法和它的clojurescript變體在javascript控制檯中,

benchmark(1000000, cljs.user.multiply); 

benchmark(1000000, function(){ 42 * 1.2 }); 

我發現

  • 本地JavaScript數學Clojure中相當於數學
  • ClojureScript是比二者都慢5-10倍

現在的問題是,如何我可以提高ClojureScript程序的性能嗎?

有一些方法到目前爲止,我認爲

  • 回落到使用可變JavaScript數組和幕後的對象。 (這可能嗎?)
  • 回到使用原生javascript數學運算符。 (這是可能的呢?)
  • 使用JavaScript陣列明確地(aget js/v 0)
  • 使用不那麼雄心勃勃實施的Clojure換的JavaScript,像https://github.com/chlorinejs/chlorinehttps://github.com/gozala/wisp他們產生更地道的JavaScript,但他們不支持命名空間我正在使用很多。

回答

10

JavaScript有明確的回報,所以

function() { 42 * 1.2 } 

什麼都不做;你會想要基準

function() { return 42 * 1.2 } 

改爲。這正好是ClojureScript版本編譯的內容,所以不會有任何區別(在ClojureScript中,非高階用法中的基本算術函數被內聯爲常規的基於運算符的JavaScript表達式)。

現在,Clojure肯定比ClojureScript更快。部分原因是Clojure比ClojureScript更加仔細地調整,儘管ClojureScript在這個部門的改進速度非常快。另一部分是Clojure有一個更成熟的JIT來利用(現代JS引擎,特別是V8,相當不錯,但目前還不是HotSpot級)。

儘管這種差異的大小有點難以衡量,涉及JIT的事實意味着一個沒有任何副作用的問題循環(如問題中的問題)很可能會被優化掉,甚至可能在第一次運行時通過它進行優化(通過使用堆棧替換,由HotSpot和使用,我認爲也是V8--但我必須檢查確定)。所以,更好的基準像

(def arr (long-array 1)) 

;;; benchmark this 
(dotimes [_ 1000000] 
    (aset (longs arr) 0 (inc (aget (longs arr) 0)))) 

longs呼籲避免Clojure的反映;也可以使用^longs提示)。

最後,在Clojure和ClojureScript中,對於某些特別對性能敏感的代碼,最好使用本機數組等等。令人高興的是,有一個與這樣做沒有問題:在ClojureScript的一面,你有arrayjs-objagetasetmake-array,你可以在方法體等領域上使用:mutable元數據deftype能夠set!他們

7

ClojureScript數學 JavaScript數學。是的,如果性能至關重要,請使用JavaScript數組和所提供的低級操作符,這些操作將保證在可能的情況下生成最佳代碼(即不存在更高的訂單使用率)。 ClojureScript持久化數據結構是這樣寫的:數組變異,算術,位旋轉。

我有一個有效的ClojureScript小例子 - http://github.com/swannodette/cljs-stl/blob/master/src/cljs_stl/spectral/demo.cljs,你可能會發現有用的指導。

+1

我以爲你在ClojureScript的某個地方有譜定律! +1。 – 2013-05-14 20:45:43