为什么使用reducers库进行映射/缩减的性能比普通map / reduce更差?
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)
我有两次杀死后两次,因为它无限期地长。这有什么不对?
修改 似乎其他语言也有类似的问题。斯卡拉似乎只打破了一百万。 Why do Scala parallel collections sometimes cause an OutOfMemoryError?。虽然clojure减速器的速度比正常速度快了一百万。
答案 0 :(得分:6)
为了补充@ a-webb的答案,这是一个编译器错误,并且涉及一个真正修复。 (See this post for more details.)
解决此问题的另一种方法是使用保险丝:
(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
答案 1 :(得分:2)
由于内存耗尽,性能正在停滞不前。如果你一直等待,你很可能会遇到内存错误。创建一个reducer将集合的头部保存在一个闭包中。因此,巨大的懒惰序列会在记忆变得紧密时占据记忆。
这是发生了什么,蒸馏
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)))
...
Christophe Grand有一个nice post关于如何以懒惰的方式构建缩减器。
答案 2 :(得分:1)
对于惰性列表,减速器并不能很好地工作,而正常的减少会有效。
要从减速器中获得真正的好处,您需要一个非惰性的集合,例如:一个向量,你需要使用fold而不是reduce。
(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"
Reducers使用fork / join Framework,它需要大量的数据块。在一个懒惰(分块)序列中,你没有这些大块,所以fork / join不能正常工作。
Rich Hickey就减速器进行了一次演讲,可以很好地解释这些概念:https://vimeo.com/45561411