Optimization 为什么内核中的函数在不绑定本地时运行得更快?
这个例子说明了这一切:Optimization 为什么内核中的函数在不绑定本地时运行得更快?,optimization,clojure,Optimization,Clojure,这个例子说明了这一切: user> (time (dotimes [i 10000000] (inc i))) "Elapsed time: 413.948711 msecs" nil user> (time (let [new-inc inc] (dotimes [i 10000000] (new-inc i)))) "Elapsed time: 1034.722729 msecs" nil 我相信编译器会内联一些核心函数,比如inc,尤其是应用于基本参数时 当您将inc用作常规
user> (time (dotimes [i 10000000] (inc i)))
"Elapsed time: 413.948711 msecs"
nil
user> (time (let [new-inc inc] (dotimes [i 10000000] (new-inc i))))
"Elapsed time: 1034.722729 msecs"
nil
我相信编译器会内联一些核心函数,比如
inc
,尤其是应用于基本参数时
当您将inc
用作常规函数时(例如,传递到高阶函数、使用let
别名等),性能可能会因此变得更差,因为它失去了内联功能。额外的开销来自于进行额外的函数调用,也可能是装箱一个或多个参数的成本
这并不是Clojure的局限性,只是反映了编译器在优化方面还不是很成熟这一事实。在Clojure的未来版本中,您可能会期望这样的事情变得更好。只是为了补充mikera提到的关于内联的内容。
inc
是绑定到函数的变量。如果您查看varinc
的meta
,即(meta#inc)
您会发现它有一个键:inliner
,编译器可以使用它的值内联使用inc var调用它的函数的代码。当您使用让在本地绑定它时,您只是将函数对象绑定到本地范围内的新名称,而函数对象没有任何内联信息,是inc
var拥有该信息,因此编译器无法内联它。这是完全正确的inc
是内联的,事实上,由于已知i
是一个原语long,编译器实际上可以发出一个字节码操作来添加1,完全绕过clojure.lang.Numbers
中的方法。