Oma*_*ena 4 arrays performance clojure
我已经读过,有一些方法可以诱使Clojure编译器生成与Java中类似代码的性能相媲美的代码,至少对于那些看起来很像你希望它变成的Java代码的代码.这对我来说听起来很合理:惯用的,高级的Clojure代码可能具有我在CPython或MRI中所使用的性能,但"丑陋"的类似Java的代码或多或少地像Java一样运行.例如,这是我在Haskell中所欣赏的权衡.低级Haskell代码具有可变数组,循环和不能在GHC下运行的适当的编译器标志,与C中的速度一样快(然后一些高科技库有时可以从更漂亮,更高级别的代码中挤出类似的性能).
我想要帮助学习如何让我的Java类Clojure代码像Java一样快速运行.举个例子:
(defn f [x y z n]
(+ (* 2 (+ (* x y) (+ (* y z) (* x z))))
(* 4 (+ x y z n -2) (- n 1))))
(defmacro from [[var ini cnd] & body]
`(loop [~var ~ini]
(when ~cnd
~@body
(recur (inc ~var)))))
(defn g [n]
(let [c (long-array (inc n))]
(from [x 1 (<= (f x x x 1) n)]
(from [y x (<= (f x y y 1) n)]
(from [z y (<= (f x y z 1) n)]
(from [k 1 (<= (f x y z k) n)]
(let [l (f x y z k)]
(aset c l (inc (aget c l))))))))
c))
(defn h [x]
(loop [n 1000]
(let [^longs c (g n)]
(if-let [k (some #(when (= x (aget c %)) %)
(range 1 (inc n)))]
k
(recur (* 2 n))))))
(time (print (h 1000)))
Run Code Online (Sandbox Code Playgroud)
使用Clojure 1.6在我的(公认的)慢速机器上需要大约85秒.Java中的等效代码在大约0.4秒内运行.我并不贪心,我只想让Clojure代码运行,比如大约2秒钟.
我做的第一件事就是启用,*warn-on-reflection*但遗憾的是,对于那种孤独的类型提示,没有进一步的警告.我究竟做错了什么?
这个要点包含代码的Java和Clojure版本.
不幸的是,*warn-on-reflection*并没有警告你关于原始拳击 - 我认为这是这里的主要问题.您希望始终使用未装箱的原始算术以获得最大速度.
以下提示应该可以帮助您优化:
(set! *unchecked-math* true)获得更快的原始数值运算(long ~ini).您希望以这种方式强制使用基元^long n到该函数中g^longs c- 这应该有希望让Clojure使用更快的原语aget.f作为原始函数^long [^long x ^long y ^long z ^long n]或类似函数.这非常重要,否则f将返回盒装数字....如果你成功地消除了所有盒装数字,那么这种代码应该和纯Java一样快.
| 归档时间: |
|
| 查看次数: |
568 次 |
| 最近记录: |