Clojure JVM 7/8 改进

发布于 2024-10-05 04:15:56 字数 273 浏览 6 评论 0原文

Rich Hickey 和其他人提到,Clojure 不会从即将为 JVM 7 或 8 计划的 invokeDynamic 中获得显着改进,但会通过尾递归获得性能提升。

尾递归会产生任何影响吗

(fn [...] (recur ...))

?或者

(loop [...] (recur ...))

我不希望它们变得更快,因为编译器可能已经生成了循环结构。

Rich Hickey and others have mentioned that Clojure will not get a significant improvement from the upcoming invokeDynamic planned for JVM 7 or 8, but will see a performance gain from tail recursion.

Will tail recursion have any effect on

(fn [...] (recur ...))

or

(loop [...] (recur ...))

I don't expect them to get any faster since the compiler probably already generates loop structures.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

筱武穆 2024-10-12 04:15:56

你的例子不会变得更快,因为如果你使用recur,你已经告诉编译器你有一个尾递归函数,这允许编译器生成使用goto的字节代码(就像普通的命令式循环一样)

如果 JVM 进行尾调用优化,当然会有一些好处。

您不必再使用 recur (如果您不想),因此您可以编写这样的函数(尾递归函数)

(defn testfn [n] (when (not= 1000 n) (testfn n)))

现在 JVM 无法检测尾递归。通过添加尾部调用优化,JVM 能够看到上面的函数,就像您编写了这个一样(因此获得命令式循环速度):

(defn testfn [n] (when (not= 1000 n) (recur n)))

所以这并不是很大的改进,但还有另一种情况,尾部调用优化是真的很棒。

如果您有相互调用的函数(有时甚至超过两个)并且不需要保留在堆栈上(尾递归),那么 JVM 可以优化它们。现在这是不可能的,因为您无法告诉 recur 跳转到其他函数。这是一个例子。

(defn even [n] (if (zero? n) true (odd? (dec n)))
(defn odd  [n] (if (zero? n) false (even (dec n)))

如果你尝试使用一个大数字,你会知道你会破坏堆栈,但通过尾部调用优化,你不会。

我所剩无几了。有一个名为 trampoline 的函数已经允许您执行此操作(编程风格稍有变化,并且有一些开销),我将向您推荐一个博客,而不是解释 trampoline正是这样做的:

http://pramode.net/clojure/2010/05 /08/clojure-蹦床/

Non your examples will get any faster because if you use recur you already tell the compiler that you have a tail recursive function and this allows the compiler to generate byte code that uses goto (like a normal imperative loop)

There is off course some benefits if the JVM gets tail call optimization.

You wont have to use recur anymore (if you don't want to) so you can write a function like this (a tail recursive function)

(defn testfn [n] (when (not= 1000 n) (testfn n)))

Nowdays the JVM is not able to detect the tail recursion. With the addition of tail call optimization the JVM able to see the function above just as if you had written this (and therefore get imperative loop speed):

(defn testfn [n] (when (not= 1000 n) (recur n)))

So that not that great of an improvement but there is another case where the tail call optimization is really great.

If you have functions that call each other (sometimes even more then two) and the do not need to hold on the the stack (are tail recursive) the JVM can optimize them. This is not possible now because you can not tell recur to jump to some other function. Here is an example.

(defn even [n] (if (zero? n) true (odd? (dec n)))
(defn odd  [n] (if (zero? n) false (even (dec n)))

If you try this with a big number know you will blow the stack but with tail call optimization you won't.

I have on little addition left. There is a function called trampoline that allow you do this already (with a little change in programming style and some overhead) Instead of explaining trampoline I will refer you to a blog that does exactly that:

http://pramode.net/clojure/2010/05/08/clojure-trampoline/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文