如何将Supervisor中首个进程生成的值传入第二个子进程规范?
问题描述
参考官方文档说明:
当Supervisor启动时,会遍历所有子进程规范,并按照定义顺序启动每个子进程。这通过调用子进程规范中:start键定义的函数完成,通常默认是start_link/1。
假设有一个Supervisor需启动两个来自不同规范的未命名进程:
第一个进程启动时会生成某个值:
@impl GenServer def init(_arg) do ... # 注意该值无需存入状态 {:ok, some_value} end
请问如何将此值作为参数传入第二个子进程规范?
期望的第二个子进程规范形式:{SomeWorker, value_from_first_worker}
解决方法
由于Supervisor初始化时就需要确定所有子进程的启动参数,无法直接从第一个子进程的init结果中动态取值传给第二个,以下是两种可行的实现思路:
方法一:手动控制子进程启动顺序
给第一个GenServer添加获取值的接口,必须把生成的
some_value存入进程状态(否则后续无法获取):defmodule FirstWorker do use GenServer def get_some_value(pid), do: GenServer.call(pid, :get_some_value) @impl GenServer def init(_arg) do some_value = generate_value() # 生成目标值的逻辑 {:ok, %{some_value: some_value}} # 将值存入状态 end @impl GenServer def handle_call(:get_some_value, _from, state) do {:reply, state.some_value, state} end defp generate_value do # 这里写生成值的具体逻辑 "example_value" end end修改Supervisor的启动函数,手动按顺序启动子进程并加入监控:
defmodule MySupervisor do use Supervisor def start_link(opts \\ []) do # 先启动空的Supervisor {:ok, supervisor_pid} = Supervisor.start_link([], strategy: :one_for_one, opts: opts) # 启动第一个子进程并加入Supervisor监控 {:ok, first_worker_pid} = Supervisor.start_child(supervisor_pid, {FirstWorker, []}) # 从第一个进程获取值 some_value = FirstWorker.get_some_value(first_worker_pid) # 用获取到的值启动第二个子进程并加入监控 Supervisor.start_child(supervisor_pid, {SomeWorker, some_value}) {:ok, supervisor_pid} end @impl Supervisor def init(_arg) do Supervisor.init([], strategy: :one_for_one) end end
方法二:由第一个进程触发第二个进程启动
调整第一个GenServer的逻辑,在
init中生成值后,主动让Supervisor启动第二个子进程:defmodule FirstWorker do use GenServer @impl GenServer def init(_arg) do some_value = generate_value() # 让指定的Supervisor启动第二个子进程 Supervisor.start_child(MySupervisor, {SomeWorker, some_value}) {:ok, %{}} # 无需存值到状态(如果后续不用的话) end defp generate_value do # 生成值的逻辑 "example_value" end end修改Supervisor的
init,只定义第一个子进程的规范:defmodule MySupervisor do use Supervisor def start_link(opts \\ []) do Supervisor.start_link(__MODULE__, opts, name: __MODULE__) end @impl Supervisor def init(_arg) do children = [ {FirstWorker, []} ] Supervisor.init(children, strategy: :one_for_one) end end
内容的提问来源于stack exchange,提问作者category
相关产品推荐
相关产品推荐

