Spec-Zone.ru › Elixir 1.7

Реестр

Локальное, децентрализованное и масштабируемое хранилище пар «ключ-значение» для процессов.

Позволяет разработчикам искать один или несколько процессов по заданному ключу. Если реестр допускает :unique ключей, ключ указывает на 0 или 1 процесс. Если реестр допускает :duplicate ключей, один ключ может указывать на любое количество процессов. В обоих случаях разные ключи могут идентифицировать один и тот же процесс.

Каждая запись в реестре связана с процессом, который зарегистрировал ключ. Если процесс завершается, ключи, связанные с этим процессом, автоматически удаляются. Все сравнения ключей в реестре выполняются с помощью операции сравнения (===/2).

Реестр может использоваться для различных целей, таких как поиск по имени (используя опцию :via), хранение свойств, пользовательские правила диспетчеризации или реализация системы публикации-подписки. Ниже мы рассмотрим некоторые из этих вариантов использования.

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

Использование в :via

После запуска реестра с заданным именем с помощью Registry.start_link/1, его можно использовать для регистрации и доступа к именованным процессам, используя кортеж {:via, Registry, {registry, key}}.

{:ok, _} = Registry.start_link(keys: :unique, name: Registry.ViaTest)
name = {:via, Registry, {Registry.ViaTest, "agent"}}
{:ok, _} = Agent.start_link(fn -> 0 end, name: name)
Agent.get(name, & &1)
#=> 0
Agent.update(name, & &1 + 1)
Agent.get(name, & &1)
#=> 1

Как правило, реестр запускается в рамках дерева надзора:

{Registry, keys: :unique, name: Registry.ViaTest}

Только реестры с уникальными ключами могут быть использованы в :via. Если имя уже занято, функция start_link, специфичная для этого случая (Agent.start_link/2 в примере выше), вернёт {:error, {:already_started, current_pid}}.

Использование в качестве диспетчера

Registry имеет механизм диспетчеризации, позволяющий разработчикам реализовывать пользовательскую логику диспетчеризации, вызываемую вызывающей стороной. Например, предположим, что у нас есть дублирующий реестр, запущенный следующим образом:

{:ok, _} = Registry.start_link(keys: :duplicate, name: Registry.DispatcherTest)

Вызвать register/3, разные процессы могут регистрироваться под заданным ключом и связывать любое значение с этим ключом. В этом случае давайте зарегистрируем текущий процесс под ключом "hello" и присоединим к нему кортеж {IO, :inspect}:

{:ok, _} = Registry.register(Registry.DispatcherTest, "hello", {IO, :inspect})

Теперь сущность, заинтересованная в диспетчеризации событий для заданного ключа, может вызвать dispatch/3, передав ключ и обратный вызов. Этот обратный вызов будет вызван со списком всех значений, зарегистрированных под запрошенным ключом, вместе с идентификатором процесса, который зарегистрировал каждое значение, в виде кортежей {pid, value}. В нашем примере, value будет кортежем {module, function} в коде выше:

Registry.dispatch(Registry.DispatcherTest, "hello", fn entries ->
  for {pid, {module, function}} <- entries, do: apply(module, function, [pid])
end)
# Prints #PID<...> where the pid is for the process that called register/3 above
#=> :ok

Диспетчеризация происходит в процессе, который вызывает dispatch/3, либо последовательно, либо параллельно в случае нескольких разделов (через запущенные задачи). Зарегистрированные процессы не участвуют в диспетчеризации, если их участие не задано явно (например, отправкой им сообщения в обратном вызове).

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

require Logger
Registry.dispatch(Registry.DispatcherTest, "hello", fn entries ->
  for {pid, {module, function}} <- entries do
    try do
      apply(module, function, [pid])
    catch
      kind, reason ->
        formatted = Exception.format(kind, reason, __STACKTRACE__)
        Logger.error "Registry.dispatch/3 failed with #{formatted}"
    end
  end
end)
# Prints #PID<...>
#=> :ok

Вы также можете заменить всю систему apply явным отправлением сообщений. Это пример, который мы рассмотрим далее.

Использование в качестве PubSub

Реестры также могут быть использованы для реализации локальной, несвязной, масштабируемой PubSub, полагаясь на функцию dispatch/3, аналогично предыдущему разделу: в этом случае, однако, мы будем отправлять сообщения каждому связанному процессу, а не вызывать заданную функцию модуля.

В этом примере мы также установим количество разделов в количестве онлайн-планировщиков, что сделает реестр более производительным в высококонкурентных средах:

{:ok, _} = Registry.start_link(keys: :duplicate, name: Registry.PubSubTest,
                               partitions: System.schedulers_online)
{:ok, _} = Registry.register(Registry.PubSubTest, "hello", [])
Registry.dispatch(Registry.PubSubTest, "hello", fn entries ->
  for {pid, _} <- entries, do: send(pid, {:broadcast, "world"})
end)
#=> :ok

В примере выше сообщение {:broadcast, "world"} было разослано всем процессам, зарегистрированным под «темой» (или «ключом», как мы его называли до сих пор) "hello".

Третий аргумент, переданный в register/3, представляет значение, связанное с текущим процессом. В предыдущем разделе мы использовали его при диспетчеризации, но в этом конкретном примере мы в нём не заинтересованы, поэтому мы установили его в пустой список. При необходимости вы можете сохранить более значимое значение.

Регистрации

Поиск, диспетчеризация и регистрация эффективны и мгновенны за счёт отложенной отписки. Например, если процесс завершается, его ключи автоматически удаляются из реестра, но изменение может не распространиться сразу. Это означает, что некоторые операции могут возвращать процессы, которые уже завершены. В документации к функциям будет явно указано, когда это может произойти.

Однако имейте в виду, что такие случаи обычно не являются проблемой. В конце концов, процесс, на который ссылается pid, может завершиться в любое время, включая период между получением значения из реестра и отправкой ему сообщения. Многие части стандартной библиотеки разработаны для работы с этим, такие как Process.monitor/1, которая будет доставлять сообщение :DOWN сразу, если отслеживаемый процесс уже завершён, и Kernel.send/2, которая действует как бездействие для завершённых процессов.

ETS

Обратите внимание, что реестр использует одну таблицу ETS плюс две таблицы ETS на раздел.

Сводка

Типы

guard()

Фильтр для проверки при сопоставлении с объектами в реестре

guards()

Список фильтров для проверки при сопоставлении с объектами в реестре

key()

Тип ключей, разрешённых при регистрации

keys()

Тип реестра

match_pattern()

Шаблон для сопоставления с объектами в реестре

meta_key()

Тип ключей метаданных реестра

meta_value()

Тип значений метаданных реестра

registry()

Идентификатор реестра

value()

Тип значений, разрешённых при регистрации

Функции

child_spec(opts)

Возвращает спецификацию для запуска реестра под управлением надзирателя

count(registry)

Возвращает количество зарегистрированных ключей в реестре. Работает за постоянное время

count_match(registry, key, pattern, guards \\ [])

Возвращает количество пар «ключ-значение» по заданному ключу в реестре, которые соответствуют шаблону

dispatch(registry, key, mfa_or_fun, opts \\ [])

Вызывает обратный вызов со всеми записями по заданному ключу в каждом разделе

keys(registry, pid)

Возвращает известные ключи для данного процесса в реестре в произвольном порядке

lookup(registry, key)

Находит пару «ключ-значение» по заданному ключу в реестре в произвольном порядке

match(registry, key, pattern, guards \\ [])

Возвращает пары «ключ-значение» по заданному ключу в реестре, которые соответствуют шаблону

meta(registry, key)

Считывает метаданные реестра по заданному ключу

put_meta(registry, key, value)

Сохраняет метаданные реестра

register(registry, key, value)

Регистрирует текущий процесс под заданным ключом в реестре

start_link(options)

Запускает реестр как процесс надзирателя

unregister(registry, key)

Удаляет все записи для данного ключа, связанные с текущим процессом в реестре

unregister_match(registry, key, pattern, guards \\ [])

Удаляет записи по заданному ключу, соответствующие шаблону

update_value(registry, key, callback)

Обновляет значение для заданного ключа текущего процесса в уникальном реестре

Типы

guard()

guard() :: {atom() | term()}

Фильтр для проверки при сопоставлении с объектами в реестре

guards()

guards() :: [guard()] | []

Список фильтров для проверки при сопоставлении с объектами в реестре

key()

key() :: term()

Тип ключей, разрешённых при регистрации

keys()

keys() :: :unique | :duplicate

Тип реестра

match_pattern()

match_pattern() :: atom() | term()

Шаблон для сопоставления с объектами в реестре

meta_key()

meta_key() :: atom() | tuple()

Тип ключей метаданных реестра

meta_value()

meta_value() :: term()

Тип значений метаданных реестра

registry()

registry() :: atom()

Идентификатор реестра

value()

value() :: term()

Тип значений, разрешённых в реестре

Функции

child_spec(opts) (с 1.5.0)

Возвращает спецификацию для запуска реестра под надзором.

См. Supervisor.

count(registry) (с 1.7.0)

count(registry()) :: non_neg_integer()

Возвращает количество зарегистрированных ключей в реестре. Выполняется за постоянное время.

Примеры

В примере ниже мы регистрируем текущий процесс и запрашиваем количество ключей в реестре:

iex> Registry.start_link(keys: :unique, name: Registry.UniqueCountTest)
iex> Registry.count(Registry.UniqueCountTest)
0
iex> {:ok, _} = Registry.register(Registry.UniqueCountTest, "hello", :world)
iex> {:ok, _} = Registry.register(Registry.UniqueCountTest, "world", :world)
iex> Registry.count(Registry.UniqueCountTest)
2

То же самое относится к дублирующим реестрам:

iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateCountTest)
iex> Registry.count(Registry.DuplicateCountTest)
0
iex> {:ok, _} = Registry.register(Registry.DuplicateCountTest, "hello", :world)
iex> {:ok, _} = Registry.register(Registry.DuplicateCountTest, "hello", :world)
iex> Registry.count(Registry.DuplicateCountTest)
2

count_match(registry, key, pattern, guards \\ []) (с 1.7.0)

count_match(registry(), key(), match_pattern(), guards()) :: non_neg_integer()

Возвращает количество пар {pid, value} по заданному key в registry, которые соответствуют pattern.

Шаблон должен быть атомом или кортежем, который будет соответствовать структуре значения, хранящегося в реестре. Атом :_ может использоваться для игнорирования данного значения или элемента кортежа, а атом :"$1" может использоваться для временного присвоения части шаблона переменной для последующего сравнения.

Необязательно можно передать список условий защиты для более точного соответствия. Каждое условие защиты — это кортеж, который описывает проверки, которые должна пройти присвоенная часть шаблона. Например, условие защиты $1 > 1 выражается как кортеж {:>, :"$1", 1}. Обратите внимание, что условия защиты будут работать только для присвоенных переменных, таких как :"$1", :"$2", и т. д. Избегайте использования специальных переменных сопоставления :"$_" и :"$$", так как они могут работать непредсказуемо.

Если соответствия нет, будет возвращено ноль.

Для уникальных реестров необходимо выполнить поиск в одной секции. Для дублирующих реестров необходимо выполнить поиск во всех секциях.

Примеры

В примере ниже мы регистрируем текущий процесс под тем же ключом в дублирующем реестре, но с различными значениями:

iex> Registry.start_link(keys: :duplicate, name: Registry.MatchTest)
iex> {:ok, _} = Registry.register(Registry.MatchTest, "hello", {1, :atom, 1})
iex> {:ok, _} = Registry.register(Registry.MatchTest, "hello", {2, :atom, 2})
iex> Registry.count_match(Registry.MatchTest, "hello", {1, :_, :_})
1
iex> Registry.count_match(Registry.MatchTest, "hello", {2, :_, :_})
1
iex> Registry.count_match(Registry.MatchTest, "hello", {:_, :atom, :_})
2
iex> Registry.count_match(Registry.MatchTest, "hello", {:"$1", :_, :"$1"})
2
iex> Registry.count_match(Registry.MatchTest, "hello", {:_, :_, :"$1"}, [{:>, :"$1", 1}])
1
iex> Registry.count_match(Registry.MatchTest, "hello", {:_, :"$1", :_}, [{:is_atom, :"$1"}])
2

dispatch(registry, key, mfa_or_fun, opts \\ []) (с 1.4.0)

dispatch(registry(), key(), dispatcher, keyword()) :: :ok
when dispatcher:
       (entries :: [{pid(), value()}] -> term()) | {module(), atom(), [any()]}

Вызывает обратный вызов со всеми записями под key в каждой секции для данного registry.

Список entries представляет собой непустой список пар из двух элементов, где первый элемент — pid, а второй элемент — значение, связанное с pid. Если для данного ключа нет записей, обратный вызов никогда не вызывается.

Если реестр разделен на секции, обратный вызов вызывается несколько раз в каждой секции. Если реестр разделен на секции и parallel: true задано как параметр, распределение происходит параллельно. В обоих случаях обратный вызов вызывается только если есть записи для этой секции.

См. документацию модуля для примеров использования функции dispatch/3 для построения пользовательского распределения или системы публикации-подписки.

keys(registry, pid) (с 1.4.0)

keys(registry(), pid()) :: [key()]

Возвращает известные ключи для данного pid в registry в произвольном порядке.

Если реестр уникальный, ключи уникальны. В противном случае они могут содержать дубликаты, если процесс был зарегистрирован под тем же ключом несколько раз. Список будет пустым, если процесс завершен или у него нет ключей в данном реестре.

Примеры

Регистрация в уникальном реестре не допускает нескольких записей:

iex> Registry.start_link(keys: :unique, name: Registry.UniqueKeysTest)
iex> Registry.keys(Registry.UniqueKeysTest, self())
[]
iex> {:ok, _} = Registry.register(Registry.UniqueKeysTest, "hello", :world)
iex> Registry.register(Registry.UniqueKeysTest, "hello", :later) # registry is :unique
{:error, {:already_registered, self()}}
iex> Registry.keys(Registry.UniqueKeysTest, self())
["hello"]

Однако это возможно для дублирующих реестров:

iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateKeysTest)
iex> Registry.keys(Registry.DuplicateKeysTest, self())
[]
iex> {:ok, _} = Registry.register(Registry.DuplicateKeysTest, "hello", :world)
iex> {:ok, _} = Registry.register(Registry.DuplicateKeysTest, "hello", :world)
iex> Registry.keys(Registry.DuplicateKeysTest, self())
["hello", "hello"]

lookup(registry, key) (с 1.4.0)

lookup(registry(), key()) :: [{pid(), value()}]

Находит пару {pid, value} для данного key в registry в произвольном порядке.

Пустой список, если нет совпадений.

Для уникальных реестров необходим поиск в одной секции. Для дублирующих реестров необходимо выполнить поиск во всех секциях.

Примеры

В примере ниже мы регистрируем текущий процесс и ищем его как из себя самого, так и из других процессов:

iex> Registry.start_link(keys: :unique, name: Registry.UniqueLookupTest)
iex> Registry.lookup(Registry.UniqueLookupTest, "hello")
[]
iex> {:ok, _} = Registry.register(Registry.UniqueLookupTest, "hello", :world)
iex> Registry.lookup(Registry.UniqueLookupTest, "hello")
[{self(), :world}]
iex> Task.async(fn -> Registry.lookup(Registry.UniqueLookupTest, "hello") end) |> Task.await()
[{self(), :world}]

То же самое относится к дублирующим реестрам:

iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateLookupTest)
iex> Registry.lookup(Registry.DuplicateLookupTest, "hello")
[]
iex> {:ok, _} = Registry.register(Registry.DuplicateLookupTest, "hello", :world)
iex> Registry.lookup(Registry.DuplicateLookupTest, "hello")
[{self(), :world}]
iex> {:ok, _} = Registry.register(Registry.DuplicateLookupTest, "hello", :another)
iex> Enum.sort(Registry.lookup(Registry.DuplicateLookupTest, "hello"))
[{self(), :another}, {self(), :world}]

match(registry, key, pattern, guards \\ []) (с 1.4.0)

match(registry(), key(), match_pattern(), guards()) :: [{pid(), term()}]

Возвращает пары {pid, value} под данным key в registry, которые соответствуют pattern.

Шаблон должен быть атомом или кортежем, который будет соответствовать структуре значения, хранящегося в реестре. Атом :_ может использоваться для игнорирования данного значения или элемента кортежа, а атом :"$1" может использоваться для временного присвоения части шаблона переменной для последующего сравнения.

Необязательно можно передать список условий защиты для более точного соответствия. Каждое условие защиты — это кортеж, который описывает проверки, которые должна пройти присвоенная часть шаблона. Например, условие защиты $1 > 1 выражается как кортеж {:>, :"$1", 1} . Обратите внимание, что условия защиты будут работать только для присвоенных переменных, таких как :"$1", :"$2", и т. д. Избегайте использования специальных переменных сопоставления :"$_" и :"$$", так как они могут работать непредсказуемо.

Если совпадений нет, будет возвращен пустой список.

Для уникальных реестров необходим поиск в одной секции. Для дублирующих реестров необходимо выполнить поиск во всех секциях.

Примеры

В примере ниже мы регистрируем текущий процесс под тем же ключом в дублирующем реестре, но с различными значениями:

iex> Registry.start_link(keys: :duplicate, name: Registry.MatchTest)
iex> {:ok, _} = Registry.register(Registry.MatchTest, "hello", {1, :atom, 1})
iex> {:ok, _} = Registry.register(Registry.MatchTest, "hello", {2, :atom, 2})
iex> Registry.match(Registry.MatchTest, "hello", {1, :_, :_})
[{self(), {1, :atom, 1}}]
iex> Registry.match(Registry.MatchTest, "hello", {2, :_, :_})
[{self(), {2, :atom, 2}}]
iex> Registry.match(Registry.MatchTest, "hello", {:_, :atom, :_}) |> Enum.sort()
[{self(), {1, :atom, 1}}, {self(), {2, :atom, 2}}]
iex> Registry.match(Registry.MatchTest, "hello", {:"$1", :_, :"$1"}) |> Enum.sort()
[{self(), {1, :atom, 1}}, {self(), {2, :atom, 2}}]
iex> Registry.match(Registry.MatchTest, "hello", {:_, :_, :"$1"}, [{:>, :"$1", 1}])
[{self(), {2, :atom, 2}}]
iex> Registry.match(Registry.MatchTest, "hello", {:_, :"$1", :_}, [{:is_atom, :"$1"}]) |> Enum.sort()
[{self(), {1, :atom, 1}}, {self(), {2, :atom, 2}}]

meta(registry, key) (с 1.4.0)

meta(registry(), meta_key()) :: {:ok, meta_value()} | :error

Считывает метаданные реестра, заданные по start_link/3.

В качестве ключей разрешены атомы и кортежи.

Примеры

iex> Registry.start_link(keys: :unique, name: Registry.MetaTest, meta: [custom_key: "custom_value"])
iex> Registry.meta(Registry.MetaTest, :custom_key)
{:ok, "custom_value"}
iex> Registry.meta(Registry.MetaTest, :unknown_key)
:error

put_meta(registry, key, value) (с 1.4.0)

put_meta(registry(), meta_key(), meta_value()) :: :ok

Хранит метаданные реестра.

В качестве ключей разрешены атомы и кортежи.

Примеры

iex> Registry.start_link(keys: :unique, name: Registry.PutMetaTest)
iex> Registry.put_meta(Registry.PutMetaTest, :custom_key, "custom_value")
:ok
iex> Registry.meta(Registry.PutMetaTest, :custom_key)
{:ok, "custom_value"}
iex> Registry.put_meta(Registry.PutMetaTest, {:tuple, :key}, "tuple_value")
:ok
iex> Registry.meta(Registry.PutMetaTest, {:tuple, :key})
{:ok, "tuple_value"}

register(registry, key, value) (с 1.4.0)

register(registry(), key(), value()) ::
  {:ok, pid()} | {:error, {:already_registered, pid()}}

Регистрирует текущий процесс под заданным key в registry.

Также необходимо указать значение, которое будет ассоциировано с этой регистрацией. Это значение будет извлекаться при вызове распределения или поиска ключа.

Эта функция возвращает {:ok, owner} или {:error, reason}. owner — pid в секции реестра, отвечающий за pid. Владелец автоматически связывается с вызывающей стороной.

Если в реестре уникальные ключи, будет возвращено {:ok, owner}, если ключ ещё не связан с pid. В противном случае возвращается {:error, {:already_registered, pid}}.

Если в реестре дублирующиеся ключи, несколько регистраций текущего процесса под одним ключом разрешены.

Примеры

Регистрация в уникальном реестре не допускает нескольких записей:

iex> Registry.start_link(keys: :unique, name: Registry.UniqueRegisterTest)
iex> {:ok, _} = Registry.register(Registry.UniqueRegisterTest, "hello", :world)
iex> Registry.register(Registry.UniqueRegisterTest, "hello", :later)
{:error, {:already_registered, self()}}
iex> Registry.keys(Registry.UniqueRegisterTest, self())
["hello"]

Однако это возможно для дублирующих реестров:

iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateRegisterTest)
iex> {:ok, _} = Registry.register(Registry.DuplicateRegisterTest, "hello", :world)
iex> {:ok, _} = Registry.register(Registry.DuplicateRegisterTest, "hello", :world)
iex> Registry.keys(Registry.DuplicateRegisterTest, self())
["hello", "hello"]

start_link(options) (с 1.5.0)

start_link(
  keys: keys(),
  name: registry(),
  partitions: pos_integer(),
  listeners: [atom()],
  meta: meta
) :: {:ok, pid()} | {:error, term()}
when meta: [{meta_key(), meta_value()}]

Запускает реестр как процесс-надзор.

Ручной запуск возможен так:

Registry.start_link(keys: :unique, name: MyApp.Registry)

В вашем дереве надзора вы напишите:

Supervisor.start_link([
  {Registry, keys: :unique, name: MyApp.Registry}
])

Для интенсивных нагрузок реестр может быть также разделен на секции (указанием параметра :partitions). Если разделение на секции необходимо, хорошим значением по умолчанию является установка количества секций на количество доступных планировщиков:

Registry.start_link(keys: :unique, name: MyApp.Registry,
                    partitions: System.schedulers_online())

или:

Supervisor.start_link([
  {Registry, keys: :unique, name: MyApp.Registry,
             partitions: System.schedulers_online()}
])

Параметры

Для реестра необходимы следующие ключи:

  • :keys - выбрать, являются ли ключи :unique или :duplicate
  • :name - имя реестра и его таблиц

Следующие ключи являются необязательными:

  • :partitions - количество секций в реестре. По умолчанию 1
  • :listeners - список имен процессов, которые уведомляются о событиях :register и :unregister. Зарегистрированный процесс должен контролироваться слушателем, если слушатель хочет быть уведомлён о сбое зарегистрированного процесса.
  • :meta - список метаданных, которые будут добавлены к реестру.

unregister(registry, key) (с 1.4.0)

unregister(registry(), key()) :: :ok

Удаляет все записи для данного key, связанные с текущим процессом в registry.

Всегда возвращает :ok и автоматически разрывает связь текущего процесса с владельцем, если больше нет ключей, связанных с текущим процессом. См. также register/3, чтобы узнать больше о «владельце».

Примеры

Для уникальных реестров:

iex> Registry.start_link(keys: :unique, name: Registry.UniqueUnregisterTest)
iex> Registry.register(Registry.UniqueUnregisterTest, "hello", :world)
iex> Registry.keys(Registry.UniqueUnregisterTest, self())
["hello"]
iex> Registry.unregister(Registry.UniqueUnregisterTest, "hello")
:ok
iex> Registry.keys(Registry.UniqueUnregisterTest, self())
[]

Для дублирующих реестров:

iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateUnregisterTest)
iex> Registry.register(Registry.DuplicateUnregisterTest, "hello", :world)
iex> Registry.register(Registry.DuplicateUnregisterTest, "hello", :world)
iex> Registry.keys(Registry.DuplicateUnregisterTest, self())
["hello", "hello"]
iex> Registry.unregister(Registry.DuplicateUnregisterTest, "hello")
:ok
iex> Registry.keys(Registry.DuplicateUnregisterTest, self())
[]

unregister_match(registry, key, pattern, guards \\ []) (since 1.5.0)

Отменить регистрацию записей для данного ключа, соответствующего шаблону.

Примеры

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

iex> Registry.start_link(keys: :unique, name: Registry.UniqueUnregisterMatchTest)
iex> Registry.register(Registry.UniqueUnregisterMatchTest, "hello", :world)
iex> Registry.keys(Registry.UniqueUnregisterMatchTest, self())
["hello"]
iex> Registry.unregister_match(Registry.UniqueUnregisterMatchTest, "hello", :foo)
:ok
iex> Registry.keys(Registry.UniqueUnregisterMatchTest, self())
["hello"]
iex> Registry.unregister_match(Registry.UniqueUnregisterMatchTest, "hello", :world)
:ok
iex> Registry.keys(Registry.UniqueUnregisterMatchTest, self())
[]

Для дублирующих регистров:

iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateUnregisterMatchTest)
iex> Registry.register(Registry.DuplicateUnregisterMatchTest, "hello", :world_a)
iex> Registry.register(Registry.DuplicateUnregisterMatchTest, "hello", :world_b)
iex> Registry.register(Registry.DuplicateUnregisterMatchTest, "hello", :world_c)
iex> Registry.keys(Registry.DuplicateUnregisterMatchTest, self())
["hello", "hello", "hello"]
iex> Registry.unregister_match(Registry.DuplicateUnregisterMatchTest, "hello", :world_a)
:ok
iex> Registry.keys(Registry.DuplicateUnregisterMatchTest, self())
["hello", "hello"]
iex> Registry.lookup(Registry.DuplicateUnregisterMatchTest, "hello")
[{self(), :world_b}, {self(), :world_c}]

update_value(registry, key, callback) (since 1.4.0)

update_value(registry(), key(), (value() -> value())) ::
  {new_value :: term(), old_value :: term()} | :error

Обновляет значение для key для текущего процесса в уникальном registry.

Возвращает кортеж {new_value, old_value} или :error, если такому ключу не назначен текущий процесс.

Если задан не уникальный регистр, генерируется ошибка.

Примеры

iex> Registry.start_link(keys: :unique, name: Registry.UpdateTest)
iex> {:ok, _} = Registry.register(Registry.UpdateTest, "hello", 1)
iex> Registry.lookup(Registry.UpdateTest, "hello")
[{self(), 1}]
iex> Registry.update_value(Registry.UpdateTest, "hello", &(&1 + 1))
{2, 1}
iex> Registry.lookup(Registry.UpdateTest, "hello")
[{self(), 2}]

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.7.4/Registry.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API