簡體   English   中英

clojure multimethods本質上是緩慢的

[英]Are clojure multimethods slow by nature

我在 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" 

這是多方法的自然結果還是存在其他問題?

Clojure multimethods允許基於任意調度函數的運行時多態行為。 這對於構建臨時層次結構和抽象非常強大,但是您為這種靈活性付出了性能損失。 您可能希望使用協議重新實現您的解決方案。 只有在需要完整的運行時類型靈活性時才使用多方法。

一般而言, 任何做得更多的事都需要更多時間 因為多方法提供了多種方式來發送,所以它們需要的時間比我必須回答的問題要長“是的,與協議相比”。

在實踐中,從協議開始,並在必要時轉到多方法(看起來你需要它們)。 你不能用代碼使計算機更快,但你可以減少它

我認為你的多方法實現較慢的原因也可能是因為你在一個惰性序列(由范圍提供)上使用reduce而不是在clojure.core中使用的遞增索引上使用loop / recur。 嘗試將clojure.core / re-groups實現的循環部分復制到第二個defmethod中,看看是否不會提高性能。

很難說沒有看到你的測試用例,但如果匹配器中有很多組,你可能會花費更多的時間將組減少為向量而不是多方法調度。 如果雖然有很少的組,那么多方法調度將花費更多的時間。 在任何一種情況下,具有相同的實現將消除對時序差異的潛在影響因素,並幫助您更好地感受多方法分派中的實際開銷。

您可能考慮的另一件事是減速可能是由於反射造成的。 嘗試將* warn-on-reflection *設置為true,看看是否有抱怨。 也許另一種戰略類型提示可能有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM