Я пытаюсь написать очень простой код, который показывает разные результаты между коммутацией и изменением в Clojure. Может ли кто-нибудь создать пример для этой цели?
Чем проще, тем лучше понять разницу.
Я пытаюсь написать очень простой код, который показывает разные результаты между коммутацией и изменением в Clojure. Может ли кто-нибудь создать пример для этой цели?
Чем проще, тем лучше понять разницу.
Предполагая, что commute
используется правильно, не должно быть никакой разницы в наблюдаемых значениях Refs, за исключением того, что использование commute
может помочь фиксации транзакции в сценарии с высокой конкуренцией, где это было бы трудно сделать с alter
. Конечно, когда это применимо, это довольно значительная разница в результате…
Легче проиллюстрировать, чем именно отличаются вещи, используя побочные эффекты. Вот однопоточный пример, иллюстрирующий основное свойство, которое
alter
будет вызываться ровно один раз за "попытку транзакции" (возможно, только один раз),
commute
будет вызываться ровно один раз за "попытку транзакции" (в то время как commute
не вызовет их, он может быть задействован в повторных попытках, если alter
используется в том же блоке dosync
), а затем в последний раз для вычисления зафиксированного значения (поэтому как минимум дважды , хотя опять же, это не вызовет повторных попыток само по себе):
user=> (def r (ref nil))
#'user/r
user=> (dosync (alter r prn))
nil
nil
user=> (dosync (commute r prn))
nil
nil
nil
Используя несколько Thread/sleep
s и несколько потоков, можно спровоцировать больше повторных попыток на стороне alter
, при этом наблюдая две повторные попытки на стороне commute
, исследовать влияние на историю ссылок использования одного или другого и т. д.