假设我有一个简单的模块
defmodule MyWorker do
def do_long_running_work(a, b, c) do
# ......
end
end
和 DynamicSupervisor
defmodule MyDynamicSupervisor do
use DynamicSupervisor
def start_link(_arg) do
DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
DynamicSupervisor.init(strategy: :one_for_one)
end
def add_my_worker(worker_name, game_id) do
child_spec = {MyWorker, {worker_name, game_id}}
DynamicSupervisor.start_child(__MODULE__, child_spec)
end
def remove_my_worker(worker_pid) do
DynamicSupervisor.terminate_child(__MODULE__, worker_pid)
end
def children do
DynamicSupervisor.which_children(__MODULE__)
end
def count_children do
DynamicSupervisor.count_children(__MODULE__)
end
end
文档说
MyWorker
必须有一个start_link
方法。此外,那里的例子表明MyWorker
是GenServer
。尽管它也可以包含 child_spec
而不必 use GenServer
但是,
MyWorker
会在 do_long_running_work()
中做一项 long-running的工作——可能持续数小时的工作。而
GenServer
本身并不意味着运行长时间运行的作业,对吗?
那我怎么去跑步
MyWorker
呢? MyWorker
的简单实现会是什么样子?
在我的情况下,
start_link
看起来不是 GenServer
是什么?
还有数以千计的
MyWorker
实例创建并运行 vis MyDynamicSupervisor
.
文档说 MyWorker 必须有一个 start_link 方法。此外,那里的例子表明 MyWorker 是 GenServer.
没有。
child specification
告诉 DynamicSupervisor 如何启动孩子:
子规范是一张最多包含6个元素的地图。这 以下列表中的前两个键是必需的,其余的 那些是可选的:
:id - 用于在内部标识子规范的任何术语 主管;默认为给定的模块。此密钥是必需的。 对于主管,如果 :id 值冲突,主管 将拒绝初始化并需要明确的 ID。这不是 不过动态主管的案例。
:start - 一个包含要调用的模块函数参数的元组以启动 子进程。这个密钥是必需的。
https://hexdocs.pm/elixir/1.14.4/Supervisor.html#module-child-specification
例如:
def add_my_worker(worker_module_name,
worker_function_name,
list_of_worker_function_args,
game_id) do
child_spec = %{
id: game_id,
start: {worker_module_name, worker_function_name, list_of_worker_function_args}
}
DynamicSupervisor.start_child(__MODULE__, child_spec)
end
你可以这样调用
add_my_worker()
:
add_my_worker(MyWorker,
:do_long_running_work,
[10, :abc, "hello"],
23561)
DynamicSupervisor 然后会调用:
spawn_link(MyWorker, :do_long_running_work, [10, :abc, "hello"])