在最近进行性能工作时,我发现将 unroll 转换为单个 assoc 调用比使用多个键快得多(对于我的特定应用程序,大约快 10%)。Zachary Tellman 后来指出,clojure.core 实际上根本不 unroll assoc,即使对于相对较低数量的键也是如此。
我们已经 unroll 了其他关键的性能函数,这些函数通过 apply
调用 things,例如 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 |
| :-- | :-- | :-- | :-- | :-- |
| 空数组映射(未 unroll) | 23ns | 93ns | 156ns | 224ns |
| 空数组映射(unroll assoc) | N/A | 51ns | 80ns | 110ns |
| | | | | |
| 20 个元素的持久 hashmap(未 unroll) | 190ns | 313ns | 551ns | 651ns |
| 20 个元素的持久 hashmap(unroll assoc) | N/A | 250ns | 433ns | 524ns |
| | | | | |
| 记录(未 unroll) | 12ns | 72ns | 105ns | 182ns |
| 记录(unroll assoc) | N/A | 21ns | 28ns | 41ns |
每次测量都在单独的 JVM 中进行,以避免 JIT 路径依赖。
基准测试在一个通用服务器(8 个 cpu,32gb ram)上运行,安装有 Ubuntu 12.04 和 Java 8 的最新版本。附件包含 cpuinfo
,uname
和 java -version
输出。
启用了相对标准的 JVM 生产标志,并注意禁用 leiningen 的启动时间优化(这会禁用许多 JIT 优化)。
可以克隆存储库并运行 script/bench
来运行基准测试。
关于此修补程序有一个待解决的问题:我们应该 unroll 多少次调用?update
(在 1.7 测试版本中已 unroll)unroll 到 3 个参数。添加更多 unroll 并不难,但这会影响 assoc 的可读性。
修补程序:CLJ-1656-v5.patch