Clojure JVM 7/8改善
-
29-09-2019 - |
質問
リッチなヒッキーなどは、Clojureが今後から大幅に改善されないと述べています invokeDynamic
JVM 7または8では計画されていますが、テールの再帰からパフォーマンスが向上します。
尾の再帰は何らかの影響を与えます
(fn [...] (recur ...))
また
(loop [...] (recur ...))
コンパイラーはおそらくすでにループ構造を生成しているため、彼らがより速くなるとは思っていません。
解決
あなたが使用する場合、あなたの例はより速くなります recur
既にコンパイラに、テール再帰機能があることを伝え、これによりコンパイラが使用するバイトコードを生成できることを伝えます goto
(通常の命令ループのように)
JVMがテールコールの最適化を取得した場合、コース外の利点があります。
もう繰り返し使用する必要はありません(したくない場合)。
(defn testfn [n] (when (not= 1000 n) (testfn n)))
現在、JVMは尾の再帰を検出できません。テールコールの最適化を追加すると、JVMはこれを書いたかのように上記の関数を見ることができます(したがって、必須ループ速度を取得します):
(defn testfn [n] (when (not= 1000 n) (recur n)))
そのため、それほど改善はあまり大きくありませんが、テールコールの最適化が本当に素晴らしい別のケースがあります。
お互いを呼び出す関数(さらに2つ以上)を持っていて、スタックを保持する必要がない場合(テール再帰的です)、JVMはそれらを最適化できます。あなたが言うことができないので、これは今は不可能です recur
他の機能にジャンプします。これが例です。
(defn even [n] (if (zero? n) true (odd? (dec n)))
(defn odd [n] (if (zero? n) false (even (dec n)))
大量にこれを試してみると、スタックを吹き飛ばすことがわかりますが、テールコールの最適化ではそうしません。
私は少し追加されています。呼ばれる関数があります trampoline
これにより、説明する代わりに、これを既に行うことができます(プログラミングスタイルといくつかのオーバーヘッドが変更されています) trampoline
まさにそれを行うブログを紹介します。