最近在进行性能工作时,我发现将关联展开为单个关联调用比使用多个键快得多(我的特定应用程序为10%)。接着Zachary Tellman指出,clojure.core根本不会展开关联,即使是对于相对较低的键数量的情况。
我们已经展开了其他通过apply调用的性能关键函数,例如update,但(我认为在大量应用程序和库的临界路径上)关联会因此受益。
我尚未为这个功能开发补丁,但我进行了一些独立的基准测试工作
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元素持久HashMap(未展开) | 190ns | 313ns | 551ns | 651ns |
| 20元素持久HashMap(展开assoc) | N/A | 250ns | 433ns | 524ns |
| | | | | |
| 记录(未展开) | 12ns | 72ns | 105ns | 182ns |
| 记录(展开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
来运行基准测试。
关于这个补丁有一个待解决的问题:我们应该展开多少调用?
补丁: CLJ-1656-v5.patch