Clojure 2024状态调查!中分享您的想法。

欢迎!请参阅关于页面了解此操作的更多信息。

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              |

**gvec**
|| f                    || before(doall)|| after(doall)|| before(chunk-last)|| after(chunk-last)||
 | {{(map inc lr)}}      | 3.69          | [3.83]       | 1.46               | 1.35              |
 | 保持标识 lr | 2.86          | 2.82         | 2.44               | 2.52              |
 | 过滤奇偶数 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的字块(chunked)序列的自定义序列可以额外从这些变化中受益。
* 相同的变化会使{{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

评论者:reborg

在CLJ-2346-2.patch中新增:在看到速度稍作提升后,将interop调用{{.count}}改为正常的{{count}}。更新了表格以反映新的基准。

0

评论者:alexmiller

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

0

评论者:reborg

因为它是在IChunk上的reduce操作,这不是通过正常的coll-reduce进行的。

0

评论者:alexmiller

如果IChunk扩展了IREduceInit,它就可以做到。

0
参考:[CLJ-2346](https://clojure.atlassian.net/browse/CLJ-2346)(由reborg报告)
...