我一直在玩Clojure 还快吗?(并且前传Clojure 是 Fast)代码。不幸的是,内联微分方程 ( f
) 是提高性能所采取的步骤之一。在不这样做的情况下,我能想到的最干净/最快的事情如下:
; 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# ( ~@expr (/ 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 并:jvm-opts ^:replace []
在 project.clj 文件中,这样我就可以使用 lein exec/run 而不会减慢速度(如果你不这样做,我发现它会...)