tl; dr:为什么代码如此慢?
我尝试优化以下代码以提高速度;它的目的是在进行n ^ 2次操作时将一个数组(大小n = 1000)转换为另一个(相同大小),转换的细节现在并不重要。
由于我试图尽可能快地获得速度,我尽可能地使用Java原语;仍然,我得到的通常是每个人约70毫秒变换'呼叫。重写到Java时,平均调用时间< 2ms的。
1)哇,Java很快
2)哇,Clojure很慢
3)你能解释一下,为什么会这样?天真地,我希望Clojure能够生成一个代码字节码,这应该与Java非常接近,为什么不是这样呢?4)我不是100%确定如何使用这些^ ints提示,也许我弄错了?
(defn transform [^ints src]
(let [res ^ints (make-array Integer/TYPE 1000)]
(loop [x (int 0)]
(if (= 1000 x) res
(do
(aset res x (areduce src i ret (int 0)
(+ ret (* (mod x 2) (mod i 3) (aget src i)))))
(recur (inc x)))))))
(let [arr (into-array Integer/TYPE (range 1000))]
(doseq [_ (range 20)]
(println (time (transform arr)))
))
答案 0 :(得分:15)
这样的事情应该更接近:
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
(defn inner ^long [^ints src ^long x]
(let [len (alength src)]
(loop [i 0 acc 0]
(if (< i len)
(recur (inc i) (+ acc (* (rem x 2) (rem i 3) (aget src i))))
acc))))
(defn transform [^ints src]
(let [res ^ints (int-array 1000)]
(loop [x 0]
(if (= 1000 x)
res
(do
(aset res x (inner src x))
(recur (inc x)))))))
(defn bench []
(let [arr (int-array (range 1000))]
(doseq [_ (range 20)]
(println (time (transform arr))))))
顶部设置对于检测错误很有用。 :warn-on-boxed one是Clojure 1.7中的新功能(目前处于测试阶段,还没有完全出现),但在这里特别有用。
我改变了一些重要的事情:
您可以将两个循环合二为一,然后再提高性能。