В недавнем выпуске Clojure 1.7 добавлено дополнение: volatile!
volatile
уже используется на многих языках, включая java, но какова семантика в Clojure?
Что он делает? Когда это полезно?
В недавнем выпуске Clojure 1.7 добавлено дополнение: volatile!
volatile
уже используется на многих языках, включая java, но какова семантика в Clojure?
Что он делает? Когда это полезно?
Новый volatile находится как можно ближе к реальной "переменной" (как и ко многим другим языкам программирования), поскольку он получает значение clojure.
От объявление:
существует новый набор функций (
volatile!
,vswap!
,vreset!
,volatile?
) для создания и использования изменчивых "ящиков" для хранения состояния в преобразователях состояния. Летучие вещества быстрее, чем атомы, но отказываются от атомных гарантий, поэтому их следует использовать только при изоляции резьбы.
Например, вы можете установить/получить и обновить их так же, как если бы вы сделали с переменной в C.
Единственным добавлением (и, следовательно, именем) является ключевое слово volatile
для фактического java-объекта.
Это предотвращает оптимизацию JVM и гарантирует, что он считывает местоположение памяти каждый раз, когда к ней обращаются. Из билет JIRA:
Clojure нужен более быстрый вариант Atom для управления внутренними преобразователями. То есть, Атомы выполняют эту работу, но они обеспечивают слишком много возможностей для целей преобразователей. В частности, семантика сравнения и свопа Атомов добавляет слишком много накладных расходов. Поэтому было установлено, что простой волатильный тип ref будет работать для обеспечения основного распространения его значения на другие потоки и чтения последней записи из любого другого потока. Хотя обновления зависят от условий гонки, доступ контролируется гарантиями JVM.
Обзор решений. Создайте конкретный тип в Java, сродни clojure.lang.Box, но волатильный внутри поддерживает IDeref, но не часы и т.д.
Это означает, что a volatile!
можно получить доступ к нескольким потокам (что необходимо для преобразователей), но оно не позволяет изменяться этими потоками одновременно, поскольку оно дает вам нет обновлений атома.
Семантика того, что делает volatile
, очень хорошо объясняется в java-ответе:
существует два аспекта безопасности потоков: (1) контроль выполнения и (2) видимость памяти. Первое связано с контролем при выполнении кода (включая порядок выполнения инструкций) и может ли он выполняться одновременно, а второй - когда эффекты в памяти о том, что было сделано, видны другим потокам. Поскольку каждый процессор имеет несколько уровней кэша между ним и основной памятью, потоки, выполняемые на разных процессорах или ядрах, могут видеть "память" по-разному в любой момент времени, поскольку потокам разрешено получать и работать с частными копиями основной памяти.
Теперь посмотрим, почему бы не использовать var-set
или transients
:
Богатый Хикки не хотел давать действительно изменяемые переменные:
Без изменчивых локальных жителей люди вынуждены использовать recur, функциональный цикл. Хотя сначала это может показаться странным, это так же кратко, как петли с мутацией, и результирующие узоры могут быть повторно используется в другом месте в Clojure, то есть повторять, уменьшать, изменять, коммутировать и т.д. все (логически) очень похожи. [...] В любом случае, Vars доступны для использования, когда это необходимо.
И, таким образом, создавая with-local-vars
, var-set
и т.д.
Проблема заключается в том, что они true vars, а строка doc var-set
сообщает вам:
var должен быть привязан к потоку.
Это, конечно, не опция для core.async, которая потенциально выполняется на разных потоках. Они также намного медленнее, потому что они выполняют все эти проверки.
Transients аналогичны тем, что они не позволяют одновременный доступ и оптимизировать мутацию структуры данных.
Проблема в том, что переходный процесс работает только с коллекцией, реализующей IEditableCollection
. То есть они просто избегают дорогого промежуточного представления структур данных сбора. Также помните, что переходные процессы не убираются на место, и вам по-прежнему необходимо некоторое место для хранения фактического переходного процесса.
Волатильности часто используются, чтобы просто удерживать флаг или значение последнего элемента (например, partition-by
)
Volatile - это не что иное, как обертка вокруг java volatile и, следовательно, такая же семантика. Никогда не делитесь ими. Используйте их только очень осторожно.
Летучие - это "более быстрый атом" без гарантий атомности. Они были представлены , поскольку атомы считались слишком медленными, чтобы удерживать состояние в преобразователях.
существует новый набор функций (
volatile!
,vswap!
,vreset!
,volatile?
) для создания и использования изменчивых "ящиков" для хранения состояния в преобразователях состояния. Летучие вещества быстрее, чем атомы, но отказываются от атомных гарантий, поэтому их следует использовать только с изолированием резьбы