Существует немного модифицированный пример из clojure.org/refsClojure коммутируют и изменять производительность
(defn mod-nth [v i f] (assoc v i (f (v i))))
(defn run [oper nvecs nitems nthreads niters]
(let [vec-refs (vec (map (comp ref vec)
(partition nitems (repeat (* nvecs nitems) 0))))
sum #(reduce + %)
swap #(let [v1 (rand-int nvecs)
v2 (rand-int nvecs)
i1 (rand-int nitems)
i2 (rand-int nitems)]
(dosync
(let [temp (nth @(vec-refs v1) i1)]
(oper (vec-refs v1) mod-nth i1 inc)
(oper (vec-refs v2) mod-nth i2 dec))))
report #(do
(prn (map deref vec-refs))
(println "Sum:"
(reduce + (map (comp sum deref) vec-refs))))]
(report)
(dorun (apply pcalls (repeat nthreads #(dotimes [_ niters] (swap)))))
(report)))
(time (run alter 100 10 10 100000))
выход образца
([0 0 0 0 0 0 0 0 0 0] [...])
Sum: 0
([15 -14 -8 57 -26 -12 -49 -29 33 -3] [...])
Sum: 0
"Elapsed time: 1995.938147 msecs"
Вместо замена уникальных номеров я передающий те из одного векторных элементов к другому ,
Эту операцию можно предположить, как коммутативный так что есть еще одно испытание - это то же самое, за исключением commute
используется вместо alter
(time (run commute 100 10 10 100000))
с выходом образца, как
([0 0 0 0 0 0 0 0 0 0] [...])
Sum: 0
([8 48 -10 -41 -17 -32 -4 50 -31 88] [...])
Sum: 0
"Elapsed time: 3141.591517 msecs"
Удивительно первый пример работает примерно в 2 seconds
, а второй - 3 seconds
Но как упоминание ред in this SO answer
commute
представляет собой оптимизированную версию изменить в те времена, когда порядок вещей на самом деле не имеет значения
Как это может быть оптимизирована в то время как требуется больше времени, чтобы сделать ту же работу в этом простой случай? Какова цель commute
?
Так что вопрос: не следует ли использовать 'alter' over' commute', когда операции транзакции крошечные? – Odomontois
Это хороший вопрос. Я бы не осмелился обобщить, хотя лучший способ, который я знаю, чтобы разобраться в таких вещах, пытается и измеряет результаты. Если бы это был я, я бы выбрал в соответствии с характером выполняемых операций (коммутативным и не коммутативным), и только тогда, если это окажется узким местом, попробуйте с другим. –
@ Odomontois, еще одна вещь, о которой следует помнить, заключается в том, что реализация Clojure может оптимизировать случай «коммутирования» в будущем. Вы даете ему больше информации о вашем коде, чтобы что-то делать, поэтому он _able_ должен быть более эффективным, будь он _actually is_ более эффективным в любой заданной точечной версии (для любого заданного блока кода) или нет. Написание кода, основанного на конкретных тестах производительности, может помочь вам при работе с одной версией, но если вы не проводите повторный бенчмаркинг при появлении новой среды выполнения Clojure ... –