see*_*equ 3 performance record clojure
好吧,标题并不完全是我想要的,但它必须在记录的成员函数访问速度中找到一个有趣的东西.我将用这个REPL会话来说明:
==> (defprotocol Add (add [_]))
Add
==> (defrecord R [x y] Add (add [_] (+ x y)))
=.R
==> (let [r (->R 1 2)] (time (dotimes [_ 100000] (add r)))) ; Pure functional style
"Elapsed time: 19.613694 msecs"
nil
==> (let [r (->R 1 2)] (time (dotimes [_ 100000] (.add r)))) ; Functional creation, but with method call
"Elapsed time: 477.29611 msecs"
nil
==> (let [r (R. 1 2)] (time (dotimes [_ 100000] (.add r)))) ; Java-style
"Elapsed time: 10.051506 msecs"
nil
==> (let [r (R. 1 2)] (time (dotimes [_ 100000] (add r)))) ; Java-style creation with functional call
"Elapsed time: 18.726801 msecs"
nil
Run Code Online (Sandbox Code Playgroud)
我无法真正看出这些差异的原因,所以我要求你这样做.
第二次调用的问题是Clojure编译器无法r在编译时确定变量的类型,因此强制使用反射.
要避免它,您应该添加类型提示:
(let [^user.R r (->R 1 2)] (time (dotimes [_ 100000] (.add r))))
Run Code Online (Sandbox Code Playgroud)
或者干脆
(let [^R r (->R 1 2)] (time (dotimes [_ 100000] (.add r))))
Run Code Online (Sandbox Code Playgroud)
它将与Java风格的方法调用一样快.
如果要在代码中轻松诊断此类问题,请将*warn-on-reflection*flag 设置为true:
(set! *warn-on-reflection* true)
Run Code Online (Sandbox Code Playgroud)
或将其添加到文件中的:global-vars部分project.clj:
:global-vars {*warn-on-reflection* true}
Run Code Online (Sandbox Code Playgroud)
所以,正如你所看到的,没有反射方法调用比函数调用快一点.但反射可能会使方法调用变得非常缓慢.