2017-02-15 12 views
0

Я новичок в Clojure и пытаюсь понять ее модель транзакции. При игре с alter и commute я заметил, что если я alter a ref после commute, то сделка ничего не совершит (или ничего не меняет).Clojure: переключение до изменения в течение одной транзакции приводит к сбою транзакции

Например:

(def counter (ref 0)) 
(def i (ref 0)) 
(future (dosync 
      (ref-set counter 1) 
      (ref-set i 1) 
      (commute counter inc) 
      (alter counter inc))) 

Оба @counter и @i будет 0, но если поменять местами commute и alter или использовать два commute с или два alter с в этом случае он будет производить желаемый результат (3 и 1, соответственно).

Я прочитал некоторые сообщения, объясняющие, что поведение commute и alter немного отличается тем, что commute фактически выполняется дважды в транзакции (один, где она стоит, другой на стадии «фиксации») и игнорирует непоследовательным снимки реф. Меня просто смущает странное поведение комбинации этих двух.

Не могли бы помочь объяснить, как это работает? Заранее спасибо!

+0

clojure 1.8: выводится в repl '{: status: failed,: val #error {: cause" Невозможно установить после коммутации ": через [{: type java.util.concurrent.ExecutionException ...' so не 'alter' после' commute'. Не удалось найти какой-либо конкретный документ для него - только [источник] (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LockingTransaction.java#L428) – birdspider

ответ

0

commute функция полезна только в очень узких (т.е. редких) случаях, когда он может уменьшить блокировки за счет дополнительных повторных попыток функции обновления. Это также делает психологическую модель транзакции более сложной, как показывает ваш пример (например, я никогда не видел эту проблему раньше, например).

ИМХО почти всегда лучше использовать alter вместо commute, так как alter прост и пуленепробиваемый. Действительно, я обычно рассматривал бы использование commute в случае преждевременной оптимизации.