當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Elixir DynamicSupervisor用法及代碼示例


Elixir語言中 DynamicSupervisor 相關用法介紹如下。

一個動態啟動孩子的主管。

Supervisor 模塊旨在處理在主管啟動時按給定順序啟動的大多數靜態子級。 DynamicSupervisor 開始時沒有子級。相反,孩子是通過 start_child/2 按需啟動的。當一個動態的supervisor終止時,所有的child同時關閉,不保證有序。

例子

一個沒有孩子的動態監督者,一個監督策略(目前唯一支持的策略是 :one_for_one )和一個名稱:

children = [
  {DynamicSupervisor, strategy: :one_for_one, name: MyApp.DynamicSupervisor}
]

Supervisor.start_link(children, strategy: :one_for_one)

子規範中給出的選項記錄在 start_link/1 中。

一旦動態主管運行,我們可以使用 start_child/2 啟動子進程,它接收子規範:

{:ok, agent1} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end})
Agent.update(agent1, &Map.put(&1, :key, "value"))
Agent.get(agent1, & &1)
#=> %{key: "value"}

{:ok, agent2} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end})
Agent.get(agent2, & &1)
#=> %{}

DynamicSupervisor.count_children(MyApp.DynamicSupervisor)
#=> %{active: 2, specs: 2, supervisors: 0, workers: 2}

基於模塊的主管

Supervisor 類似,動態監管者也支持基於模塊的監管者。

defmodule MyApp.DynamicSupervisor do
  # Automatically defines child_spec/1
  use DynamicSupervisor

  def start_link(init_arg) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  @impl true
  def init(_init_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end
end

請參閱 Supervisor 文檔,了解何時可能需要使用基於模塊的主管。緊接在use DynamicSupervisor 之前的@doc 注釋將附加到生成的 child_spec/1 函數。

名稱注冊

主管與 GenServer 綁定到相同的名稱注冊規則。在 GenServer 的文檔中閱讀有關這些規則的更多信息。

從主管遷移:simple_one_for_one

如果您使用的是 Supervisor 模塊中已棄用的 :simple_one_for_one 策略,則可以通過幾個步驟遷移到 DynamicSupervisor

想象一下給定的"old" 代碼:

defmodule MySupervisor do
  use Supervisor

  def start_link(init_arg) do
    Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  def start_child(foo, bar, baz) do
    # This will start child by calling MyWorker.start_link(init_arg, foo, bar, baz)
    Supervisor.start_child(__MODULE__, [foo, bar, baz])
  end

  @impl true
  def init(init_arg) do
    children = [
      # Or the deprecated: worker(MyWorker, [init_arg])
      %{id: MyWorker, start: {MyWorker, :start_link, [init_arg]}}
    ]

    Supervisor.init(children, strategy: :simple_one_for_one)
  end
end

它可以像這樣升級到DynamicSupervisor:

defmodule MySupervisor do
  use DynamicSupervisor

  def start_link(init_arg) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  def start_child(foo, bar, baz) do
    # If MyWorker is not using the new child specs, we need to pass a map:
    # spec = %{id: MyWorker, start: {MyWorker, :start_link, [foo, bar, baz]}}
    spec = {MyWorker, foo: foo, bar: bar, baz: baz}
    DynamicSupervisor.start_child(__MODULE__, spec)
  end

  @impl true
  def init(init_arg) do
    DynamicSupervisor.init(
      strategy: :one_for_one,
      extra_arguments: [init_arg]
    )
  end
end

不同之處在於 DynamicSupervisor 在調用 start_child/2 時需要子規範,而不是在 init 回調中。如果在初始化時給出了任何初始參數,例如 [initial_arg] ,則可以在 DynamicSupervisor.init/1 :extra_arguments 標誌中給出。

相關用法


注:本文由純淨天空篩選整理自elixir-lang.org大神的英文原創作品 DynamicSupervisor。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。