2024年Clojure 运行状况调查! 中分享您的想法。

欢迎!请参阅 关于 页面以获取更多关于该功能如何工作的信息。

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

**长范围**
|| f                    || 在 doGetall 之前 || 在 doGetall 之后 || 在 doChunk-last 之前 || 在 doChunk-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                    || 在 doGetall 之前 || 在 doGetall 之后 || 在 doChunk-last 之前 || 在 doChunk-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                    || 在 doGetall 之前 || 在 doGetall 之后 || 在 doChunk-last 之前 || 在 doChunk-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                    || 在 doGetall 之前 || 在 doGetall 之后 || 在 doChunk-last 之前 || 在 doChunk-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              |

所有基准测试都在新鲜启动的 JVM 上使用 "bench" 实现,并且丢弃了具有大异常变异的结果。所使用的通用基准模板形式如下:{{(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 新增:观察到微小的速度提升后,将间]", inv的调用从 {{.count}} 改为 {{count}}。已更新表格,以反映新的基准测试。

0

评论者:alexmiller

为什么使用 .reduce 而不是 reduce?

0

评论者:reborg

因为在 IChunk 上的 reduce 没有通过正常的 coll-reduce 暴露。

0

评论者:alexmiller

如果 IChunk 扩展了 IReduceInit,那么这可能行得通。

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