我一直在玩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次/它沒有類型提示在任f
或solveit
),但它仍然比內聯版本低近2倍。最終這個表現還是相當不錯的,但是這次打擊是不幸的。
爲什麼會有這樣的性能打擊?有沒有辦法解決它?有沒有計劃尋找改進這種方法的方法?正如John在原文中指出的那樣,函數調用在功能語言中效率低下似乎很有趣/不幸。
注:我正在運行Clojure 1.5,並在project.clj文件中有:jvm-opts ^:replace []
,這樣我就可以使用lein exec/run而不會減慢速度(如果不這樣做,我會發現.. )
哇...非常感謝你。我讀過clojure中的性能分析是JVM的一個棘手的原因,但我認爲這種差異只是微小的。我只是使用時間和長凳分析了一個20倍差距的功能! – metasoarous