clojure - 为什么 Clojure 的 core.reducers 比惰性集合函数更快

标签 clojure functional-programming reducers

在许多关于Reducers的资源中(如 the canonical blog post by Rich Hickey ),声称Reducers比常规集合函数((map ... (filter ...)) 等)更快,因为开销更少。

可以避免哪些额外开销? IIUC 即使是惰性收集函数最终也会遍历原始序列一次。中间结果的计算细节是否有差异?

指向 Clojure 实现中有助于理解差异的相关位置的指针也将是最有帮助的

最佳答案

我认为一个关键的见解来自 original blog post 的以下段落。 :

(require '[clojure.core.reducers :as r])
(reduce + (r/filter even? (r/map inc [1 1 1 2])))
;=> 6

That should look familiar - it's the same named functions, applied in the same order, with the same arguments, producing the same result as the Clojure's seq-based fns. The difference is that, reduce being eager, and these reducers fns being out of the seq game, there's no per-step allocation overhead, so it's faster. Laziness is great when you need it, but when you don't you shouldn't have to pay for it.

延迟序列的实现会带来(线性)分配成本:每当延迟序列中的另一个元素被实现时,seq 的剩余部分就会存储在一个新的 thunk 中,并且这种“thunk”的表示是 a new clojure.lang.LazySeq object .

我相信那些LazySeq对象是引用中提到的分配开销。使用reducers,不会逐渐实现lazy seq元素,因此根本不会实例化LazySeq thunk。

关于clojure - 为什么 Clojure 的 core.reducers 比惰性集合函数更快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36011719/

相关文章:

clojure - 在惰性序列中思考

java - 搜索 JDK 等效项以在收集流时进行转换

javascript - 如何连接到数组中的 'indexed' 对象

javascript - 在 JavaScript 中返回一个带有一些额外属性的新对象

hadoop - 映射器何时将其输出存储到本地硬盘?

loops - 无法通过逐个元素循环来更新向量

clojure - lein ring uberjar -- java.lang.NoClassDefFoundError : clojure/lang/Var

dictionary - 除了 map 和矢量之外,get 在 Clojure 中还有其他用途吗?

c# - 遍历列表列表?

java - 以函数式风格递归遍历对象链