当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。