PartitionSupervisor
Начальник, который запускает несколько разделов одного и того же дочернего элемента.
Некоторые процессы могут стать узкими местами в больших системах. Если состояние этих процессов можно тривиально разделить, при этом между ними нет зависимости, то они могут использовать PartitionSupervisor для создания нескольких изолированных и независимых разделов.
После запуска PartitionSupervisor вы можете отправлять запросы дочерним элементам, используя {:via, PartitionSupervisor, {name, key}}, где name — имя PartitionSupervisor, а ключ используется для маршрутизации.
Пример
Начальник DynamicSupervisor — это единый процесс, ответственный за запуск других процессов. В некоторых приложениях DynamicSupervisor может стать узким местом. Для решения этой проблемы вы можете запустить несколько экземпляров DynamicSupervisor через PartitionSupervisor, а затем выбрать случайный экземпляр для запуска дочернего элемента.
Вместо запуска одного DynamicSupervisor:
children = [
{DynamicSupervisor, name: MyApp.DynamicSupervisor}
]
Supervisor.start_link(children, strategy: :one_for_one)
и запуска дочерних элементов непосредственно на этом динамическом начальнике:
DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end})
Вы можете запустить динамические начальники под PartitionSupervisor:
children = [
{PartitionSupervisor,
child_spec: DynamicSupervisor,
name: MyApp.DynamicSupervisors}
]
Supervisor.start_link(children, strategy: :one_for_one)
и затем:
DynamicSupervisor.start_child(
{:via, PartitionSupervisor, {MyApp.DynamicSupervisors, self()}},
{Agent, fn -> %{} end}
)
В приведенном выше коде мы запускаем начальника раздела, который по умолчанию запускает динамический начальник для каждого ядра вашего компьютера. Затем вместо вызова DynamicSupervisor по имени вы вызываете его через начальника раздела, используя формат {:via, PartitionSupervisor, {name, key}}. Мы выбрали self() в качестве ключа маршрутизации, что означает, что каждый процесс будет назначен одному из существующих динамических начальников. См. start_link/1, чтобы увидеть все поддерживаемые опции PartitionSupervisor.
Примечания по реализации
PartitionSupervisor использует таблицу ETS или Registry для управления всеми разделами. Внутри PartitionSupervisor генерирует спецификацию дочернего элемента для каждого раздела и затем действует как обычный начальник. Идентификатор каждой спецификации дочернего элемента — это номер раздела.
Для маршрутизации используются две стратегии. Если key является целым числом, оно маршрутизируется с помощью rem(abs(key), partitions), где partitions — количество разделов. В противном случае используется :erlang.phash2(key, partitions). Конкретная маршрутизация может измениться в будущем, и поэтому на ней нельзя полагаться. Если вы хотите получить конкретный PID для определенного ключа, вы можете использовать GenServer.whereis({:via, PartitionSupervisor, {name, key}}).
Резюме
Типы
Функции
- count_children(supervisor)
-
Возвращает карту, содержащую значения подсчета для начальника.
- partitions(name)
-
Возвращает количество разделов для начальника раздела.
- start_link(opts)
-
Запускает начальника раздела с заданными параметрами.
- stop(supervisor, reason \\ :normal, timeout \\ :infinity)
-
Синхронно останавливает данный начальник раздела с заданным
reason. - which_children(name)
-
Возвращает список с информацией обо всех дочерних элементах.
Типы
name()Исходный код
@type name() :: atom() | {:via, module(), term()}Имя PartitionSupervisor.
Функции
count_children(supervisor)Исходный код
@spec count_children(name()) :: %{
specs: non_neg_integer(),
active: non_neg_integer(),
supervisors: non_neg_integer(),
workers: non_neg_integer()
}Возвращает карту, содержащую значения подсчета для начальника.
Карта содержит следующие ключи:
:specs— количество разделов (дочерних процессов):active— количество всех активно работающих дочерних процессов, управляемых этим начальником:supervisors— количество всех начальников, независимо от того, жив ли дочерний процесс:workers— количество всех рабочих процессов, независимо от того, жив ли дочерний процесс
partitions(name)Исходный код
@spec partitions(name()) :: pos_integer()
Возвращает количество разделов для начальника раздела.
start_link(opts)Исходный код
@spec start_link(keyword()) :: Supervisor.on_start()
Запускает начальника раздела с заданными параметрами.
Эта функция обычно не вызывается напрямую, вместо этого она вызывается при использовании PartitionSupervisor в качестве дочернего элемента другого начальника:
children = [
{PartitionSupervisor, child_spec: SomeChild, name: MyPartitionSupervisor}
]
Если начальник успешно запущен, эта функция возвращает {:ok, pid}, где pid — PID начальника. Если заданное имя для начальника раздела уже назначено процессу, функция возвращает {:error, {:already_started, pid}}, где pid — PID этого процесса.
Обратите внимание, что начальник, запущенный с помощью этой функции, связан с родительским процессом и завершается не только при сбоях, но и если родительский процесс завершается с :normal причиной.
Параметры
:name— атом или кортеж, представляющий имя начальника раздела (см.name/0).:partitions— положительное целое число с количеством разделов. По умолчаниюSystem.schedulers_online()(обычно количество ядер).:strategy— стратегия перезапуска, по умолчанию:one_for_one. Вы можете узнать больше о стратегиях в документации модуляSupervisor.:max_restarts— максимальное количество перезапусков, разрешенных в рамках времени. По умолчанию3.:max_seconds— временной интервал, в котором применяется:max_restarts. По умолчанию5.:with_arguments— анонимная функция с двумя аргументами, которая позволяет передать раздел функции запуска дочернего элемента. См. раздел:with_argumentsниже.
:with_arguments
Иногда вы хотите, чтобы каждый раздел знал свой назначенный номер раздела. Это можно сделать с помощью параметра :with_arguments. Эта функция получает список аргументов спецификации дочернего элемента и раздел. Она должна вернуть новый список аргументов, которые будут переданы спецификации дочернего элемента дочерних элементов.
Например, большинство процессов запускаются вызовом start_link(opts), где opts — список ключевых слов. Вы можете внедрить раздел в параметры, передаваемые дочернему элементу:
with_arguments: fn [opts], partition -> [Keyword.put(opts, :partition, partition)] end
stop(supervisor, reason \\ :normal, timeout \\ :infinity)Исходный код
@spec stop(name(), reason :: term(), timeout()) :: :ok
Синхронно останавливает данный начальник раздела с заданной reason.
Возвращает :ok если начальник завершается с указанной причиной. Если он завершается по другой причине, вызов завершается.
Эта функция сохраняет семантику OTP относительно сообщения об ошибках. Если причина отличается от :normal, :shutdown или {:shutdown, _}, регистрируется сообщение об ошибке.
which_children(name)Исходный код
@spec which_children(name()) :: [
{:undefined, pid() | :restarting, :worker | :supervisor,
[module()] | :dynamic}
]Возвращает список с информацией обо всех дочерних элементах.
Эта функция возвращает список кортежей, содержащих:
id— номер разделаchild— PID соответствующего дочернего процесса или атом:restartingесли процесс собирается перезапуститьсяtype—:workerили:supervisorкак определено в спецификации дочернего элементаmodules— как определено в спецификации дочернего элемента
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.14.1/PartitionSupervisor.html