【发布时间】:2015-02-18 06:10:05
【问题描述】:
多方法比协议慢,当协议可以解决问题时,应该尝试使用协议,即使使用多方法提供了更灵活的解决方案。
那么cond 和多方法是什么情况呢?它们可用于解决相同的问题,但我的猜测是多方法与cond 相比具有巨大的性能开销。如果是这样,我为什么要使用多方法而不是 cond?
【问题讨论】:
标签: clojure
多方法比协议慢,当协议可以解决问题时,应该尝试使用协议,即使使用多方法提供了更灵活的解决方案。
那么cond 和多方法是什么情况呢?它们可用于解决相同的问题,但我的猜测是多方法与cond 相比具有巨大的性能开销。如果是这样,我为什么要使用多方法而不是 cond?
【问题讨论】:
标签: clojure
多方法允许开放扩展;其他人可以通过在其源中添加新的defmethods 来扩展您对任意表达式的多方法调度。 Cond 表达式在不编辑 cond 源代码的情况下被其他人甚至您自己的代码关闭。
如果您只想根据条件逻辑采取行动,那么 cond 就是您要走的路。如果您想要进行更复杂的调度,或者对具有不同行为的多种类型的数据应用一个函数,那么多方法可能更合适。
【讨论】:
什么时候可以测量?
这是使用criterium 库的基准示例。 Cond 和 Multi-methods 代码取自 http://blog.8thlight.com/myles-megyesi/2012/04/26/polymorphism-in-clojure.html。
警告 这只是一个比较multimethod 和cond 性能的基准测试示例。下面的结果表明cond 的性能优于multimethod,在实践中不能推广到各种用法。您可以将此基准测试方法用于您自己的代码。
【讨论】:
为了跟进@AlexMiller 的评论,我尝试使用更多随机数据进行基准测试,并添加了协议实现(还添加了一种类型 - 整数 - 到不同的方法中)。
(defprotocol StrConvert
(to-str [this]))
(extend-protocol StrConvert
nil
(to-str [this] "null")
java.lang.Integer
(to-str [this] (str this))
java.lang.String
(to-str [this] (str "\"" this "\""))
clojure.lang.Keyword
(to-str [this] (to-str (name this)))
java.lang.Object
(to-str [this] (str this)))
data 包含 10000 个随机整数的序列,这些整数随机转换为 String、nil、keyword 或 vector。
(let [fns [identity ; as is (integer)
str ; stringify
(fn [_] nil) ; nilify
#(-> % str keyword) ; keywordize
vector] ; vectorize
data (doall (map #(let [f (rand-nth fns)] (f %))
(repeatedly 10000 (partial rand-int 1000000))))]
;; print a summary of what we have in data
(println (map (fn [[k v]] [k (count v)]) (group-by class data)))
;; multimethods
(c/quick-bench (dorun (map convert data)))
;; cond-itionnal
(c/quick-bench (dorun (map convert-cond data)))
;; protocols
(c/quick-bench (dorun (map to-str data))))
结果是 data 包含:
([clojure.lang.PersistentVector 1999] [clojure.lang.Keyword 1949]
[java.lang.Integer 2021] [java.lang.String 2069] [nil 1962])
我当然会建议 @DanielCompton :设计比每种方法看起来配对的纯粹性能更重要,至少在这个例子中。
【讨论】: