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

欢迎!请参阅 关于 页面,了解更多关于该功能的信息。

+9
Clojure

在最近进行性能工作期间,我发现将 assoc 展开为单个调用要显著快于使用多个键(对于我的特定应用,大约 10%)。接着 Zachary Tellman 指出,clojure.core 在相当低数量的键的情况下根本不会展开 assoc。

我们已将其他性能关键函数展开,例如通过 apply 调用的 update https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L5914,但我认为 assoc(对于大量应用和库是关键路径)将从这中受益。

我尚未开发针对此问题的补丁,但我进行了一些独立基准测试。

https://github.com/yeller/unrolling-assoc-benchmarks

基准测试结果

代码: https://github.com/yeller/unrolling-assoc-benchmarks/blob/master/src/bench_assoc_unrolling.clj

| |1 |2 |3 |4 |
| :-- | :-- | :-- | :-- | :-- |
| 空数组映射(未展开) | 23ns | 93ns | 156ns | 224ns |
| 空数组映射(展开 assoc) | N/A | 51ns | 80ns | 110ns |
| | | | | |
| 20 个元素的持久化哈希表(未展开) | 190ns | 313ns | 551ns | 651ns |
| 20 个元素的持久化哈希表(展开 assoc) | N/A | 250ns | 433ns | 524ns |
| | | | | |
| 记录(未展开) | 12ns | 72ns | 105ns | 182ns |
| 记录(展开 assoc) | N/A | 21ns | 28ns | 41ns |

每个测量都是在单独的 JVM 中进行的,以避免 JIT 路径依赖。

基准测试在商业服务器(8 个 CPU,32gb 内存)上运行,使用 ubuntu 12.04 和 Java 8 的最新版本。附上 cpuinfounamejava -version 输出。

启用了相对标准的 JVM 生产标志,并小心禁用了 leiningen 的启动时间优化(这将禁用许多 JIT 优化)。

可以通过克隆存储库并运行 script/bench 来运行基准测试。

对于这个补丁有一个悬而未决的问题:应该展开多少次这些调用?update(在 1.7 测试版中被展开)展开到 3 个参数。增加展开并不困难,但它会影响 assoc 的可读性。

补丁: CLJ-1656-v5.patch

25 答案

投票数:0

评论者:alexmiller

是的,内联是通过变量调用实现的。

投票数:0

评论者:tcrayford

Michael,

这个组只是是你已经上传的clojure master版本,你的补丁已应用,构建方式和之前一样(你应该能检出仓库并复制)。

投票数:0

评论者:alexmiller

补丁CLJ-1656-v5.patch似乎对旧版本的联想并没有实际影响(在core.clj的约179行)?

新版本需要具有arglists以及其他类似内容。我不确定那里面的宏/私有变量。你尝试过使用RT.assocN()与向量结合吗?

测试套件中是否已有针对联想N对的测试?

投票数:0

评论者:michaelblume

clojure.core中的依赖关系使得联想必须在语法引用之前定义得很好,所以我让它定义了两次,一次较慢,一次较快。我会提供一个带有arglists的补丁。是否需要为每个新参数提供arglists,或者现有的arglists足够了?(我担心我对arglists元数据的作用不够肯定)对联想现有测试的缺少让人烦恼。我在我的树中有一些生成性测试,因为它似乎比为所有不同的参数性写用例更有趣。如果它看起来 useful,我可以发表它,但可能是一种过度。

投票数:0

评论者:michaelblume

这就是我提到的测试补丁,比我记得的更过头了

投票数:0

评论者:michaelblume

好了,这里有代码和测试。

这也验证了在 varargs 的情况下,assoc! 传入的 kvs 个数是偶数,这是 assoc 的行为。测试验证了 assoc 和 assoc! 都会在奇数参数数量时抛出异常。

投票数:0

评论者:alexmiller

现有的 arglist 是好的——它只是为了文档目的覆盖了自动生成的那个。

你试过任何 RT.assocN() 东西吗?

我想问的另一个问题是,人们实际上是否这样做得足够多以至于这很重要? :)

投票数:0

评论者:michaelblume

更新补丁以应用于 master

投票数:0

评论者:alexmiller

这还需要对不同计数频率的评估。根据一些非常快速的检查,传递两个 kvs 已经足够常见以至于很重要。传递三个远不如常见,等等。但我很想看到通过运行某些东西而得到的频率的大致想法。我认为当前的展开太多(2-3 个 kvs 可能就足够了)。

投票数:0
参考: https://clojure.atlassian.net/browse/CLJ-1656 (由 tcrayford 报告)
...