Я пытаюсь узнать Clojure из API и документации, доступной на сайте. Я немного неясен в отношении изменяемого хранилища в Clojure, и я хочу убедиться, что мое понимание верное. Пожалуйста, дайте мне знать, есть ли какие-то идеи, которые я неправильно понял.
Изменить: я обновляю это, когда получаю комментарии о его правильности.
Отказ от ответственности: вся эта информация является неформальной и потенциально неправильной. Не используйте этот пост, чтобы понять, как работает Clojure.
Vars всегда содержит привязку корня и, возможно, привязку к потокам. Они сопоставимы с регулярными переменными на императивных языках и не подходят для обмена информацией между потоками. (спасибо Артуру Ульфельду)
Refs - это места, разделяемые между потоками, которые поддерживают атомные транзакции, которые могут изменять состояние любого количества ссылок в одной транзакции. Транзакции совершаются при выходе из выражений синхронизации (dosync), и конфликты разрешаются автоматически с помощью магии STM (откаты, очереди, ожидания и т.д.).
Агенты - это местоположения, которые позволяют асинхронно делиться информацией между потоками с минимальными накладными расходами путем отправки независимых функций действия для изменения состояния агента. Агенты немедленно возвращаются и, следовательно, не блокируются, хотя значение агента не установлено до тех пор, пока функция отправки не будет завершена.
Атомы - это места, которые могут синхронно совместно использоваться потоками. Они поддерживают безопасную манипуляцию между различными потоками.
Здесь мое дружеское резюме, основанное на том, когда использовать эти структуры:
- Вары похожи на обычные старые переменные в императивных языках. (избегайте, когда это возможно)
- Атомы похожи на Vars, но с безопасностью обмена нитями, что позволяет быстро считывать и безопасно устанавливать. (спасибо Мартину)
- Агент как Atom, но вместо того, чтобы блокировать его, генерирует новый поток для вычисления его значения, только блокирует, если он находится в середине изменения значения, и может позволить другим потокам знать, что он завершил назначение.
- Refs - это общие местоположения, которые блокируются в транзакциях. Вместо того, чтобы программист решал, что происходит во время условий гонки для каждой части заблокированного кода, мы просто запускаем транзакцию и позволяем Clojure обрабатывать все условия блокировки между ссылками в этой транзакции.
Кроме того, связанная концепция представляет собой функцию future
. Для меня кажется, что будущий объект можно охарактеризовать как синхронный Агент, где невозможно получить доступ к значению до тех пор, пока вычисление не будет завершено. Он также может быть описан как неблокирующий Atom. Являются ли эти точные концепции будущего?