agetパフォーマンスに関するこの質問のフォローアップ
最適化に関しては、非常に奇妙なことが起こっているようです。私たちは次のことが真実であることを知っていました。
=> (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)
反射の警告やヒントは必要ありません。同じ動作は、agetをルートvarまたはletにバインドすることで見られます。
=> (let [f aget] (time (reduce + (for [x xa] (f xa x)))))
"Elapsed time: 43.912129 msecs"
4999950000
バインドされたagetが最適化する方法を「知っている」ように見える理由はありますか?コア関数はそうではありませんか?