7

私はclojure.core 関数の再グループ化を見ていました:

(defn re-groups [^java.util.regex.Matcher m]
    (let [gc  (. m (groupCount))]
      (if (zero? gc)
        (. m (group))
        (loop [ret [] c 0]
          (if (<= c gc)
            (recur (conj ret (. m (group c))) (inc c))
             ret))))) 

そして、マルチメソッドとして書き直した方が「良い」と思いました:

(defmulti re-groups (fn [^java.util.regex.Matcher m] (.groupCount m)))
(defmethod re-groups 0 [m] (.group m))
(defmethod re-groups :default [m]
        (let [idxs (range (inc (.groupCount m)))]
             (reduce #(conj %1 (.group m %2)) [] idxs))) 

それでも、時間を比較すると、書き換えが 4 倍遅いことに驚きました。

clojure.core: "Elapsed time: 668.029589 msecs"
multi-method: "Elapsed time: 2632.672379 msecs" 

これはマルチメソッドの自然な結果ですか、それとも他に何か問題がありますか?

4

3 に答える 3

4

Clojure のマルチメソッドは、任意のディスパッチ関数に基づいた実行時のポリモーフィック動作を可能にします。これは、アドホックな階層と抽象化を構築するのに非常に強力ですが、そのような柔軟性のためにパフォーマンス ヒットが発生します。プロトコルを使用してソリューションを再実装することをお勧めします。完全な実行時の型の柔軟性が必要な場合にのみ、マルチメソッドを使用してください。

于 2011-08-31T17:34:36.357 に答える
3

一般に、より多くのことを行うと、より多くの時間がかかります。マルチメソッドはさまざまなディスパッチ方法を提供するため、プロトコルよりも時間がかかります。「プロトコルと比較した場合、はい」という質問に答える必要があります。

実際には、プロトコルから始めて、必要なときにマルチメソッドに進みます(そして、それらが必要なように見えます)。コードを使ってコンピューターを高速化することはできませんが、実行速度を下げることはできます

于 2011-08-31T21:17:16.483 に答える
0

I think the reason your multi-method implementation is slower may also be because you are using reduce on a lazy sequence (provided by range) instead of the loop/recur on an incrementing index that is used in clojure.core. Try copying the loop part of the implementation of clojure.core/re-groups into your second defmethod and see if that doesn't increase the performance.

It is hard to say without seeing your test case, but if there are a lot of groups in the matcher, you may be spending much more time in reducing the groups into a vector than in the multi-method dispatch. If there are few groups though, then the multi-method dispatch will be a more significant portion of the time spent. In either case, having the same implementation will eliminate a potential contributing factor to the timing difference and help you to get a better feel for the actual overhead in multi-method dispatch.

Another thing you might consider is the possibility that the slowdown is due to reflection. Try setting *warn-on-reflection* to true and see if it complains. Maybe another strategic type hint may help.

于 2011-09-01T09:09:15.353 に答える