这个例子说明了一切:
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
这个例子说明了一切:
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 提到的关于内联的内容。Theinc
是绑定到函数的 var。如果您查看meta
of var inc
ie (meta #'inc)
,您会发现它有一个键,编译器可以使用其值来内联使用 inc var:inliner
调用它的函数的代码。当您使用在本地绑定它时,您只是将函数对象绑定到本地范围内的新名称,并且函数对象没有任何内联信息,它是具有该信息的 var,因此编译器无法内联它。let
inc