Ответы:
Я настоятельно рекомендую "The Joy of Clojure" или "Программирование Clojure" для реального ответа на этот вопрос, я могу воспроизвести короткий фрагмент мотивации для каждого из них:
начните с просмотра этого видео о понятии идентичности и / или изучите здесь .
Скоординированный доступ используется, когда два удостоверения должны измениться вместе, классический пример - перевод денег с одного банковского счета на другой, он должен либо перемещаться полностью, либо не перемещаться вообще.
Некоординированный доступ используется, когда требуется обновить только одно удостоверение, это очень распространенный случай.
Синхронный доступ используется, когда ожидается, что вызов будет ждать, пока не будут установлены все идентификаторы, прежде чем продолжить.
Асинхронный доступ - это «выстрелил и забыл», и позволить Identity достичь своего нового состояния в свое время.
ensure
функции: clojure.github.io/clojure/clojure.core-api.html#clojure.core/…, чтобы сделать это явным и более эффективным.
Ссылки предназначены для состояния, которое необходимо синхронизировать между потоками. Если вам нужно отслеживать кучу разных вещей, и иногда вам нужно выполнять операции, которые записывают сразу несколько вещей, используйте refs. Каждый раз, когда у вас есть несколько разных частей состояния, использование ссылок - неплохая идея.
Атомы предназначены для независимого состояния, которое необходимо синхронизировать между потоками. Если вам никогда не понадобится одновременно изменять состояние атома и что-либо еще, использование at atom безопасно (в частности, если во всей программе есть только один фрагмент состояния, вы можете поместить его в атом) . В качестве нетривиального примера, если вы пытаетесь кэшировать возвращаемые значения функции (то есть запоминать ее), использование атома, вероятно, безопасно - состояние невидимо для всего, что находится за пределами функции, поэтому вам не нужно беспокоиться об изменении состояния внутри функции, что-то испортило.
Основная цель агентов заключается в том, что они работают в другом потоке. Вы можете получить значение агента и сказать ему применить функцию к его значению, но вы не знаете, когда функция будет запущена или к какому значению она будет применена.
Переменные используются, когда вам нужно хранить что-то для каждого потока. Если у вас многопоточная программа, и каждому потоку требуется собственное частное состояние, поместите это состояние в переменную.
Что касается реальных примеров, то если вы приведете пример того, что пытаетесь сделать, мы можем сказать вам, что использовать.
Когда я впервые прочитал об этих типах, я также изо всех сил пытался понять, где я могу или должен использовать каждый из них, поэтому вот мой простой английский ответ:
Используйте переменную, если данные не изменяются. Это происходит всякий раз, когда вы используете def
или большинство функций, которые начинаются с def
like defn
.
Используйте атом, если у вас есть один изменяемый элемент. Примером может быть счетчик или вектор, в который вы хотите добавить элементы.
Используйте реф, если у вас есть две или более вещи, которые должны измениться одновременно. Подумайте о «транзакциях базы данных», если вы знакомы. Канонический пример этого - перевод денег с одного счета на другой. Каждую учетную запись можно сохранить в ссылке, чтобы изменения могли быть атомарными.
Используйте агента, когда хотите что-то изменить, но вам все равно, когда. Это может быть долгое вычисление или запись чего-либо в файл или сокет. Обратите внимание, что с последним вы должны использовать send-off
.
Примечание. Я понимаю, что каждый из них содержит гораздо больше, но, надеюсь, это послужит вам отправной точкой.
Я написал статью, в которой резюмировал разницу между ними и помог выбрать, какой из них использовать.
Поделиться состоянием - когда используются вары, атомы, агенты и ссылки?
Надеюсь, это поможет людям, ищущим ответы в этой теме.
Некоторый ярлык из статьи после предложения @tunaci:
Варс
Варки глобальны для каждого потока.
Не изменяйте вары после создания. Это технически возможно, но по многим причинам это плохая идея.
Атомы
Делитесь доступом к изменяемому состоянию для каждого потока. Смена происходит синхронно. Повторите попытку, когда другой поток изменит состояние во время выполнения.
Не используйте неидемпотентные функции и функции с длительным исполнением
Агенты
Делитесь доступом к изменяемому состоянию для каждого потока. Изменение происходит асинхронно.
Refs
Refs работает аналогично транзакциям с базой данных. Запись и чтение защищены в dosync. Вы можете работать со многими рефери, безопасно в сделке.
И блок-схема при использовании какой из них:
Пожалуйста, посмотрите изображение на сайте, потому что обновления возможны всегда.
Это сложная и длинная тема, чтобы дать полный ответ без копирования и прошлой статьи, поэтому, пожалуйста, простите меня, я перенаправляю вас на сайт :)
атомы, ссылки и агенты - немного освещения здесь http://blog.jayfields.com/2011/04/clojure-state-management.html
state-a
, но при этом ссылаюсьstate-b
, мне все равно нуженref
правильный? Значит, это не изменение нескольких вещей, а ссылка на несколько вещей при изменении любого из них?