评论由:jdevuyst创建
嗯。我想这个惰性序列确实导致了大量的分配。
好的,我重写了我的测试并再次运行了几次。现在我也在向量和数组上进行了测试。
补丁1需要微小调整。当调用 coll-fold 时,补丁1只为类型 {{object}} 指定回退(即调用 r/reduce)。我必须为类型 {{array}} 添加相同的回退。(这很奇怪!)
所以这里是结果。
对于向量
`
(let [coll (vec (repeat 100 (vec (range 100))))]
(time (dotimes [n 3000]
(->> coll
(r/mapcat identity)
(r/map inc)
(r/filter even?)
(r/fold +)))))
`
补丁1: 205872毫秒
补丁2: 210756毫秒
对于数组
`
(let [coll (into-array (repeat 100 (into-array (range 100))))]
(time (dotimes [n 3000]
(->> coll
(r/mapcat identity)
(r/map inc)
(r/filter even?)
(r/fold +)))))
`
补丁1: 123567毫秒
补丁2: 119704毫秒
我多次运行了我的测试,结果非常一致。补丁1在向量大大领先,而补丁2在数组上更快。
这在情理之中。
在补丁1中,{{reducer}} 将直接调用 {{-reduce}}。而在补丁2中,{{reducer}} 首先调用 {{r/reduce}},如果集合是向量,则调用 {{-reduce}},如果集合是数组,则调用 {{array-reduce}}。因此,在向量的情况下,补丁2将包含额外的函数调用,但在数组的情况下避免了在本地类型上调用协议方法。
使用宏(或复制粘贴)可以避免额外的函数调用。这值得尝试吗?或者,保持代码整洁是否更重要?
--
我刚刚意识到,补丁2在语义上与 Clojure 的实现略有不同,尽管这可能是一个 Clojure 的错误:[https://groups.google.com/forum/#!searchin/clojure-dev/kv-reduce/clojure-dev/bEqECvbExGo/iW4B2vEUh8sJ](https://groups.google.com/forum/#!searchin/clojure-dev/kv-reduce/clojure-dev/bEqECvbExGo/iW4B2vEUh8sJ)。我建议使用宏(或复制粘贴)来避免补丁2中的额外函数调用,这也可能解决这个问题。