私は、ClojureのパフォーマンスがJavaと同等の立場にあることを証明しようとしています。私が見つけた重要なユースケースはクイックソートです。私は次のように実装を書きました:
(set! *unchecked-math* true)
(defn qsort [^longs a]
(let [qs (fn qs [^long low, ^long high]
(when (< low high)
(let [pivot (aget a low)
[i j]
(loop [i low, j high]
(let [i (loop [i i] (if (< (aget a i) pivot)
(recur (inc i)) i))
j (loop [j j] (if (> (aget a j) pivot)
(recur (dec j)) j))
[i j] (if (<= i j)
(let [tmp (aget a i)]
(aset a i (aget a j)) (aset a j tmp)
[(inc i) (dec j)])
[i j])]
(if (< i j) (recur i j) [i j])))]
(when (< low j) (qs low j))
(when (< i high) (qs i high)))))]
(qs 0 (dec (alength a))))
a)
また、これはJavaクイックソートを呼び出すのに役立ちます。
(defn jqsort [^longs a] (java.util.Arrays/sort a) a))
さて、ベンチマークのために。
user> (def xs (let [rnd (java.util.Random.)]
(long-array (repeatedly 100000 #(.nextLong rnd)))))
#'user/xs
user> (def ys (long-array xs))
#'user/ys
user> (time (qsort ys))
"Elapsed time: 163.33 msecs"
#<long[] [J@3ae34094>
user> (def ys (long-array xs))
user> (time (jqsort ys))
"Elapsed time: 13.895 msecs"
#<long[] [J@1b2b2f7f>
パフォーマンスは世界的に異なります(桁違いに、そしていくつか)。
私が見逃しているものはありますか、私が使用した可能性のあるClojure機能はありますか?パフォーマンス低下の主な原因は、ループからいくつかの値を返す必要があり、そのためのベクトルを割り当てる必要がある場合だと思います。これは避けられますか?
ところで、Clojure1.4を実行しています。また、HotSpotをウォームアップするために、ベンチマークを複数回実行したことにも注意してください。これらは彼らが落ち着く時です。
アップデート
私のコードの最もひどい弱点は、ベクトルの割り当てだけでなく、それらがボクシングを強制し、プリミティブチェーンを壊すという事実です。もう1つの弱点は、結果を使用することです。これは、結果loop
もチェーンを切断するためです。はい、Clojureでのパフォーマンスはまだ地雷原です。