请在《2024 Clojure状态调查!》中分享您的想法。

欢迎!请参阅关于页面以了解更多有关此方式的信息。

0
Clojure
当在{{ArrayChunk}}上调用{{reduce}}而不是当前的{{dotimes}}时,分块序列处理会显示出一般性的改进。受影响的函数有{{map}}、{{filter}}和{{keep}}。以下表格显示了相关的基准测试(单位:毫秒)。括号中的数字比原始状态差(尽管只略有差距)。在长范围内看到最好的整体改进。

长范围
|| f                    || before(doall)|| after(doall)|| before(chunk-last)|| after(chunk-last)||
 | {{(map inc lr)}}      | 3.75          | 2.88         | 2.15               | 2.06              |
 | {{(keep identity lr)}}| 2.56          | 2.16         | 0.75               | 0.72              |
 | {{(filter odd? lr)}}  | 2.77          | 2.20         | 1.53               | 1.45              |

范围
|| f                    || before(doall)|| after(doall)|| before(chunk-last)|| after(chunk-last)||
 | {{(map inc lr)}}      | 3.64          | [3.70]       | 2.32               | [2.50]            |
 | {{(keep identity lr)}}| 2.10          | 1.94         | 0.56               | 0.46              |
 | {{(filter odd? lr)}}  | 1.95          | [1.99]       | 1.19               | [1.66]            |

向量
|| f                    || before(doall)|| after(doall)|| before(chunk-last)|| after(chunk-last)||
 | {{(map inc lr)}}      | 3.81          | 3.68         | 2.44               | 2.15              |
 | {{(keep identity lr)}}| 2.03          | [2.16]       | 0.53               | 0.46              |
 | {{(filter odd? lr)}}  | 2.08          | [2.82]       | 1.67               | 1.39              |

广义向量
|| f                    || before(doall)|| after(doall)|| before(chunk-last)|| after(chunk-last)||
 | {{(map inc lr)}}      | 3.69          | [3.83]       | 1.46               | 1.35              |
 | {{(keep identity lr)}}| 2.86          | 2.82         | 2.44               | 2.52              |
 | {{(filter odd? lr)}}  | 2.95          | 2.70         | 2.08               | 2.07              |

所有基准测试均使用 "bench" 策略在新的 JVM 上执行,并丢弃变异程度大的结果。使用的基准模板形式为:{{(let [xs chunked-seq] (bench (doall (f xs))))}} 其中

* "chunked-seq" 可能为以下之一:{{(range 100000)}}, {{(range 1e5)}}, {{(vec (range 1e5))}} 或 {{(into (vector-of :int) (range 1e5))}}
* "doall" 是 {{doall}} 或 {{chunk-last}}(请参见以下定义)
* "f" 是以下之一:{{(map inc xs)}}, {{(filter odd? xs)}} 或 {{(keep identity xs)}}。

观测结果

* 块的大小和数量越大,收益越大。具有大于 32 的块大小的自定义(分块)序列可以从中额外受益。
* 相同的改动对 {{keep-indexed}} 和 {{map-indexed}} 有负面影响,因此它们没有被修改。
* {{for}} 宏也意识到了块,但它使用显式循环来处理以下情况:{{:let, :when, :while}},这难以与块缓冲区更改分离。
* {{chunk-last}} 是一个块意识函数,用于通过块访问最后一个元素。与按顺序遍历的 {{doall}} 相比,{{chunk-last}} 更有效,适用于在更改代码之前和之后。函数如下:{{(defn chunk-last [xs] (when-let [xs (seq xs)] (if-let [cn (chunk-next xs)] (recur cn) (last xs))))}}
* 在 {{{map}}} 定义之前,对 {{dotimes}} 的初始非正式预处理可以在核心中删除。这包含在补丁中。

8 答案

0
by

评论由:alexmiller 撰写

你能合并补丁吗?

0
by

评论由:reborg 撰写

当然可以。

0
by

评论由:alexmiller 撰写

谢谢!

0
by

评论由:reborg 撰写

新在 CLJ-2346-2.patch 中:在看到速度略有改善后,将 interop 调用的 {{.count}} 改为正常的 {{count}}。已更新表以反映新的基准。

0

评论由:alexmiller 撰写

有什么原因使用.reduce而不是reduce?

0

评论由:reborg 撰写

因为它在IChunk上的reduce,这不是通过正常coll-reduce公开。

0

评论由:alexmiller 撰写

如果IChunk扩展IReduceInit,则可能就是这样。

0
...