Мультиметоды медленнее протоколов, и следует попытаться использовать протоколы, когда они могут решить проблему, хотя использование мультиметодов дает более гибкое решение. Так что же происходит с cond
и мультиметодом? Они могут быть использованы для решения одной и той же проблемы, но я предполагаю, что у мультиметода есть огромная служебная нагрузка против cond
. Если да, то почему я хотел бы использовать multimethod вместо cond
?Производительность multimethod vs cond в Clojure
ответ
Чтобы следить за @AlexMiller комментарий, я попытался бенчмарка с большим количеством рандомизированных данных и суммируется реализацию протокола (также добавил еще один тип - Integer - для различных методов).
(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])
- Мультиметоды: 6,26 мс
- Cond-itionnal: 5,18 мс
- Протоколы: 6.04 мс
Я несомненно, предложили бы @DanielCo mpton: дизайн имеет большее значение, чем чистые характеристики, кажущиеся на пару для каждого метода, по крайней мере, на этом примере.
Мультиметоды допускают открытое расширение; другие могут распространять вашу многоточную диспетчеризацию на произвольные выражения. Выражения Cond закрыты для расширения другими или даже вашим собственным кодом.
Если вы просто хотите действовать на условной логике, то конд - это путь. Если вы хотите выполнять более сложную диспетчеризацию или применять функцию по многим типам данных с различным поведением, то, вероятно, более целесообразным будет использовать многометод.
Зачем беспокоиться, когда вы можете измерить?
Вот эталонный образец с использованием библиотеки criterium. Cond
и Multi-methods
коды взяты с http://blog.8thlight.com/myles-megyesi/2012/04/26/polymorphism-in-clojure.html.
Caveat Это просто пример делать тест сравнения multimethod
и cond
производительности. Результат ниже - то, что показывает cond
, работает лучше, чем multimethod
, не может быть обобщен для различного использования на практике. Вы можете использовать этот метод бенчмаркинга для своего собственного кода.
;; cond (defn convert-cond [data] (cond (nil? data) "null" (string? data) (str "\"" data "\"") (keyword? data) (convert-cond (name data)) :else (str data))) (bench (convert-cond "yolo")) Evaluation count : 437830380 in 60 samples of 7297173 calls. Execution time mean : 134.822430 ns Execution time std-deviation : 1.134226 ns Execution time lower quantile : 133.066750 ns (2.5%) Execution time upper quantile : 137.077603 ns (97.5%) Overhead used : 1.893383 ns Found 2 outliers in 60 samples (3.3333 %) low-severe 2 (3.3333 %) Variance from outliers : 1.6389 % Variance is slightly inflated by outliers ;; multimethod (defmulti convert class) (defmethod convert clojure.lang.Keyword [data] (convert (name data))) (defmethod convert java.lang.String [data] (str "\"" data "\"")) (defmethod convert nil [data] "null") (defmethod convert :default [data] (str data)) (bench (convert "yolo")) Evaluation count : 340091760 in 60 samples of 5668196 calls. Execution time mean : 174.225558 ns Execution time std-deviation : 1.824118 ns Execution time lower quantile : 170.841203 ns (2.5%) Execution time upper quantile : 177.465794 ns (97.5%) Overhead used : 1.893383 ns nil
Вы не должны доверять этому эталону - вы только конвертируете один тип, что приводит к оптимальному пути кода в обоих случаях (сайт мономорфного вызова в мультиметоде). Лучше протестировать с помощью рандомизированной смеси типов ввода (идеально подходящей для вашего реального кода). –
- 1. Clojure cond или если?
- 2. Clojure multimethod с несколькими значениями отправки
- 3. Можно ли запрашивать значения отправки clojure multimethod?
- 4. clojure like cond in F #
- 5. Консолидированные аргументы Cond в Clojure (стиль CL)
- 6. Помогите мне написать Cond Macro в Clojure
- 7. подходящий тип данных в clojure с core.match/match вместо multimethod
- 8. Карты Clojure vs. «Real»
- 9. Clojure Cassandra Производительность драйвера
- 10. Число Takeuchi в Clojure (производительность)
- 11. Двоичный поиск в clojure (реализация/производительность)
- 12. Создайте матрицу Multitrait-Multimethod
- 13. mini-kanren В чем разница между cond-cond-u и cond-e?
- 14. Cascalog deffilterop vs pure clojure
- 15. cond with large clauses
- 16. Clojure коммутируют и изменять производительность
- 17. Clojure^floats vs. #^floats?
- 18. Clojure: rest vs. next
- 19. clojure pmap vs map
- 20. Lein Clojure 1.3 vs Clojure 1.2.1
- 21. Clojure apply vs map
- 22. Производительность Ilnumerics в Mono vs VS
- 23. Как улучшить производительность обработки текста в Clojure?
- 24. URI vs Производительность файла
- 25. VARCHAR vs DECIMAL Производительность
- 26. Производительность: Pig vs Hive
- 27. Производительность char vs string
- 28. Производительность sprintf vs String.Format
- 29. Весна - Развязка Vs Производительность
- 30. Производительность System.IO.File vs System.IO.FileStream
Но сколько накладных расходов вводит во многих вариантах vs cond? – user3139545
Согласен. Используйте тот подход, который лучше всего подходит для вашей конкретной задачи, и беспокоиться о производительности позже. – Alex