Performance clojure的多种方法天生就慢吗

Performance clojure的多种方法天生就慢吗,performance,clojure,multimethod,Performance,Clojure,Multimethod,我是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

我是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))))) 
然而,当比较时间时,我惊讶地发现重写速度慢了4倍:

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

这是多方法的自然结果还是有其他问题?

Clojure多方法允许基于任意调度函数的运行时多态行为。这对于构建特别的层次结构和抽象来说是非常强大的,但是您需要为这种灵活性付出性能上的代价。您可能希望使用协议重新实现您的解决方案。只有在您需要完全的运行时类型灵活性时才使用multi-methods。

一般来说,任何做得更多的事情都会花费更多的时间。因为多方法提供了多种调度方式,它们比协议花费的时间更长,所以我必须回答您的问题“是的,与协议相比”


实际上,从协议开始,并在必要时使用多方法(看起来您需要它们)。你不能用代码让计算机更快,但你可以让它做得更少。我认为你的多方法实现更慢的原因也可能是因为你在惰性序列(由range提供)上使用reduce,而不是在clojure.core中使用的递增索引上使用loop/recur。尝试将clojure.core/re-groups实现的循环部分复制到第二个defmethod中,看看这是否不会提高性能

很难说没有看到您的测试用例,但是如果matcher中有很多组,那么将这些组缩减为向量所花费的时间可能比多方法分派所花费的时间要多得多。如果组很少,那么多方法调度将是所花费时间中更重要的部分。在这两种情况下,使用相同的实现将消除造成时间差异的潜在因素,并帮助您更好地了解多方法调度中的实际开销


另一件你可能会考虑的是减速是由于反射造成的。尝试设置为true,看看是否有问题。也许另一种策略类型的提示可能有帮助。

我考虑了一个协议,但是从<代码>中得到的函数在第一个参数的类型上调度,因此必须至少有一个参数,需要的是对该参数的
进行分派。您似乎在这里使用多方法作为一种模式匹配构造。这并不是multimethod的目的,它是(多)分派。可以把它看作是面向对象语言中可能发生的事情的超集。对于单次分派(像普通的OO一样),使用协议。对于模式匹配,请使用以下方法:另外,clojure.core代码正是出于性能原因,因此大多数其他实现都会更慢。我使用此方法来获取计时:
(时间(计数(映射重新匹配(循环[#“[-+]?[0-9]+/([0-9])+“#”([-+]?[0-9]+)/([0-9]+)/([0-9]+]?[0-9]+]?[0-9]+“#”仓鼠])(范围为[x])(范围x)](str x/“y(()(()))
clojure.core: "Elapsed time: 668.029589 msecs"
multi-method: "Elapsed time: 2632.672379 msecs"