2013-11-10 39 views
1

我一直在玩Is Clojure is Still Fast?(和prequel Clojure is Fast)代碼。內省微分方程(f)是改善性能的一個步驟似乎很不幸。我已經能夠拿出不這樣做的乾淨/最快的是以下幾點:函數調用爲什麼在clojure中放慢速度?

; As in the referenced posts, for giving a rough measure of cycles/iteration (I know this is a very rough 
; estimate...) 
(def cpuspeed 3.6) ;; My computer runs at 3.6 GHz 
(defmacro cyclesperit [expr its] 
    `(let [start# (. System (nanoTime)) 
     ret# ([email protected] (/ 1.0 ~its) ~its) 
     finish# (. System (nanoTime))] 
    (println (int (/ (* cpuspeed (- finish# start#)) ~its))))) 

;; My solution 
(defn f [^double t ^double y] (- t y)) 
(defn mysolveit [^double t0 ^double y0 ^double h ^long its] 
    (if (> its 0) 
    (let [t1 (+ t0 h) 
      y1 (+ y0 (* h (f t0 y0)))] 
     (recur t1 y1 h (dec its))) 
    [t0 y0 h its])) 
; => 50-55 cycles/it 

; The fastest solution presented by the author (John Aspden) is 
(defn faster-solveit [^double t0 ^double y0 ^double h ^long its] 
    (if (> its 0) 
    (let [t1 (+ t0 h) 
      y1 (+ y0 (* h (- t0 y0)))] 
     (recur t1 y1 h (dec its))) 
    [t0 y0 h its])) 
; => 25-30 cycles/it 

在我的解決方案的類型提示幫助了不少(這是224次/它沒有類型提示在任fsolveit),但它仍然比內聯版本低近2倍。最終這個表現還是相當不錯的,但是這次打擊是不幸的。

爲什麼會有這樣的性能打擊?有沒有辦法解決它?有沒有計劃尋找改進這種方法的方法?正如John在原文中指出的那樣,函數調用在功能語言中效率低下似乎很有趣/不幸。

注:我正在運行Clojure 1.5,並在project.clj文件中有:jvm-opts ^:replace [],這樣我就可以使用lein exec/run而不會減慢速度(如果不這樣做,我會發現.. )

回答

10

存在JIT編譯器時的基準測試非常棘手;你真的必須允許一個熱身期,但是你也不能只是把它全部循環運行,因爲它可能會被證明沒有運行並被優化掉。在Clojure中,通常的解決方案是使用Hugo Duncan的Criterium

競選(solveit 0.0 1.0 (/ 1.0 1000000) 1000000)solveit結果幾乎一模一樣的時機在我的機器(mysolveit〜3.44毫秒,faster-solveit〜3.45毫秒)兩個版本繞圈基準。這是在使用Criterium 0.4.2(criterium.core/bench)的-XX:+UseConcMarkSweepGC 64位JVM運行。推測HotSpot只是內聯f。無論如何,沒有任何性能問題。

+0

哇...非常感謝你。我讀過clojure中的性能分析是JVM的一個棘手的原因,但我認爲這種差異只是微小的。我只是使用時間和長凳分析了一個20倍差距的功能! – metasoarous

相關問題