评论者:jdevuyst
Hm. 我想这会导致大量分配。
好的,我已经重写了我的测试并运行了几次。现在我也在矢量和数组上进行了测试。
补丁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)。我建议使用宏(或复制粘贴)来避免补丁2中的额外函数调用,这也可以解决这种差异。