2013-11-07 3 views
3

Что такое компромиссы представления состояния с использованием одного атома и hashmap vs multiple refs?Single atom vs multiple refs

Например:

(def start (atom {:location "Chicago" :employer "John"})) 

против

(def location (ref "Chicago")) 
(def employer (ref "John")) 

Большое спасибо

ответ

3

Одиночная версия атом лучше и имеет меньше компромиссов. Учитывая, что вы не хотите менять работодателя и местоположение несогласованным, ваша победа заключается в том, что вам не нужно создавать блок dosync для изменения местоположения или работодателя или того и другого. Используя атом, вы можете просто (swap! start assoc :location "baz").

Большая часть использования нескольких ссылок заключается в том, что все транзакции с рефери будут проверяться параллельно, а первый, кто готов, победит, остальные будут перезапущены. Хотя это верно и для атомов, наличие дополнительных ссылок для всех записей требует большего контроля, группировки (для блоков dosync) и т. Д. За кулисами. Чтобы иметь меньше перезагрузок, имеет смысл группировать информацию на хэш-карте. В зависимости от того, требуется ли скоординированное изменение, поместите его в ref или атом.

1

Я не думаю, что вы должны думать о компромиссах между atoms против refs, так как они используются для разных ситуаций.

Вы должны использовать atom, если хотите что-то изменить atomically.

refs использовать STM и включать в себя различные вещи, которые изменяются одновременно, в транзакции.

В вашей конкретной ситуации вы должны отвечать на вопрос о том, что вы меняете.

  • Это одна вещи, которую вы хотите/может изменить в одном шаге
  • Существуют различные вещи, которые вы хотите/потребность изменить транзакционно

При переключении старой базы данных для новых базу данных и изменить все вместе, чтобы изменить одно поле, и поэтому вы говорите, что ваша база данных - atom, вы злоупотребляете механизмом.

Надеюсь, что это различие помогает, для вашего примера я бы использовал атом, тем не менее.

Существует good summary here с мотивами, стоящими за каждой стратегией.

2

Несколько Refs позволяют использовать больше параллелизма, поскольку все записи в Atom линеаризуются. STM позволяет совершать много параллельных транзакций, когда нет конфликтующих записей/ensure s (и дополнительно он обеспечивает commute, что позволяет делать определенные записи, которые обычно приводят к конфликту, чтобы не делать этого).

Кроме того, STM сотрудничает с агентами - действия, отправленные агентам из транзакции, будут выполняться в том случае и только в случае совершения транзакции.Это позволяет безопасно вызывать побочные эффекты внутри транзакции. Атомы не предлагают подобного объекта.

Компромисс - это накладные расходы STM больше, чем Atom, плюс есть возможность возникновения определенных аномалий (написать перекос, см. the Wikipedia page on snapshot isolation). Кроме того, можно добиться большого параллелизма с STM, имея серьезные проблемы с получением моментальной копии всей системы; в этой связи, см. превосходный Кристоф Гранд blog post и его библиотеку megaref.

Во многих сценариях люди находят, что достаточно просто сохранить все состояние в одном атоме, и это определенно более простой и легкий подход.

+0

+1 для сбалансированного ответа, но это немного смутило меня; 'Кроме того, STM взаимодействует с агентами - действия, отправленные агентам из транзакции, будут выполняться тогда и только тогда, когда транзакция совершает транзакции.' - Не будут ли выполняться действия при замене атома? Это означает, что действия будут выполняться независимо от успеха. – muhuk

+0

Если вы «отправляете» из функции, переданной 'swap!', То да, 'send' будет переустанавливаться при каждой попытке. Попробуйте, например. '(def a (atom 0)) (def ag (агент nil)) (do (future (swap! a (fn [x] (Thread/sleep 5000) (send ag println: foo) (inc x)))) (Thread/sleep 1000) (swap! A inc)) ': здесь': foo' будет печататься дважды; если вы использовали Ref вместо Atom, он будет печататься только один раз. –

+0

Вы правы. Спасибо за пример! – muhuk