CLOJURE REFUCERSライブラリのパフォーマンスを調整します
質問
Refuctors Libraryでマッピング/縮小しているのは、通常のマップ/削減よりも悪い性能を持っていますか?
user=> (time (reduce + (map inc (range 100000000))))
"Elapsed time: 14412.627966 msecs"
5000000050000000
user=> (time (reduce + (r/map inc (range 100000000))))
... (C-c)
user=> (time (r/reduce + (r/map inc (range 100000000))))
....(C-c)
.
私は2つの後者の殺害があると無期限に長くかかる。ここで何が悪いの?
編集: 他の言語も同様の問題もあります。Scalaは百万人だけで壊れているようです。 Scala Parallel CollectionsがOutOfMemoryErrorを発生させることがあるのはなぜですか?。Clojure Defuctorsは100万人で通常より速いです。
解決
@ a-webbの答えを補完するために、これはコンパイラのバグと、本当に修正するための関与のものです。(詳細については、この記事を参照してください。)
問題を回避するもう1つの方法は、 FUSE を使用することです。:
(defn once-seq
"Returns a sequence on which seq can be called only once."
[coll]
(let [a (atom coll)]
(reify clojure.lang.Seqable
(seq [_]
(let [coll @a]
(reset! a nil)
(seq coll))))))
.
、次に
=> (time (r/reduce + (r/map inc (once-seq (range 100000000)))))
"Elapsed time: 3692.765 msecs"
5000000050000000
. 他のヒント
メモリが使い果たされているので、性能は停止に研削されています。待っている場合は、メモリエラーが発生する可能性が最も高いです。減速機を作成すると、コレクションの先頭をクロージャーに保持します。したがって、膨大な遅延シーケンスは実現されるにつれてメモリを上昇させます。
これが何が起こっているのか、蒸留
user=> (def n 100000000)
#'user/n
user=> (time (dorun (range n)))
"Elapsed time: 12349.034702 msecs"
.
今も同じですが、クロージャー内から
user=> (defn foo [x] (fn [f] (f x)))
#'user/foo
user=> (time ((foo (range n)) dorun))
OutOfMemoryError GC overhead limit exceeded ... (sometime later)
.
と比較してください
(time (do (doall (range n)) nil))
OutOfMemoryError GC overhead limit exceeded ... (sometime later)
.
還元剤の疑わしい閉鎖
user=> (source r/folder)
(defn folder
"Given a foldable collection, [...]"
{:added "1.5"}
([coll xf]
(reify
clojure.core.protocols/CollReduce
(coll-reduce [_ f1]
(clojure.core.protocols/coll-reduce coll (xf f1) (f1)))
...
.
縮小剤は遅延リストでは実際にはうまくいかないが、通常の減少は行います。
再契約者のうちに本当の利益を得るために、あなたは非怠惰なコレクションを必要とします。ベクトルとあなたは減少の代わりに折り目を使う必要があります。
(def v (into [] (range 10000000)))
(time (reduce + (map inc v)))
;; "Elapsed time: 896.79 msecs"
(time (reduce + (r/map inc v)))
;; "Elapsed time: 671.947 msecs"
(time (r/fold + (r/map inc v)))
;; "Elapsed time: 229.45 msecs"
.
縮小剤は、大きなデータのチャンクを必要とするフォーク/結合フレームワークで動作します。怠惰な(チャンクされた)シーケンスでは、これらの大きなチャンクを持っていませんので、フォーク/結合はうまく機能できません。
概念を説明する還元剤では豊富なHickeyによる話があります。 https://vimeo.com/45561411