跟进这个关于get性能的问题
在优化方面似乎有一些非常奇怪的事情。我们知道以下情况是正确的:
=> (def xa (int-array (range 100000)))
#'user/xa
=> (set! *warn-on-reflection* true)
true
=> (time (reduce + (for [x xa] (aget ^ints xa x))))
"Elapsed time: 42.80174 msecs"
4999950000
=> (time (reduce + (for [x xa] (aget xa x))))
"Elapsed time: 2067.673859 msecs"
4999950000
Reflection warning, NO_SOURCE_PATH:1 - call to aget can't be resolved.
Reflection warning, NO_SOURCE_PATH:1 - call to aget can't be resolved.
然而,一些进一步的实验真的让我很奇怪:
=> (for [f [get nth aget]] (time (reduce + (for [x xa] (f xa x)))))
("Elapsed time: 71.898128 msecs"
"Elapsed time: 62.080851 msecs"
"Elapsed time: 46.721892 msecs"
4999950000 4999950000 4999950000)
没有反射警告,不需要提示。通过将 get 绑定到根 var 或 let 可以看到相同的行为。
=> (let [f aget] (time (reduce + (for [x xa] (f xa x)))))
"Elapsed time: 43.912129 msecs"
4999950000
知道为什么绑定的 get 似乎“知道”如何优化,而核心功能不知道吗?