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