为什么simple_one_for_one工作人员可以共享相同的Child Spec Id?

why*_*why 1 erlang erlang-otp

我为一个名为band_supervisor的主管定义了simple_one_for_one工作规范,子规范id是jam_musician:

  init([]) ->
    {ok, {{simple_one_for_one, 3, 60},
    [{jam_musician,
    {musicians, start_link, []},
    temporary, 1000, worker, [musicians]}
    ]}};
Run Code Online (Sandbox Code Playgroud)

音乐家模块是:

-module(musicians).
-behaviour(gen_server).

-export([start_link/2, stop/1]).
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3, terminate/2]).

-record(state, {name="", role, skill=good}).
-define(DELAY, 750).

start_link(Role, Skill) ->
  gen_server:start_link({local, Role}, ?MODULE, [Role, Skill], []).

stop(Role) -> gen_server:call(Role, stop).
Run Code Online (Sandbox Code Playgroud)

我可以通过以下方式创建许多工人:

3> supervisor:start_child(band_supervisor, [drum, good]).
Musician Arnold Ramon, playing the drum entered the room
{ok,<0.696.0>}
3> supervisor:start_child(band_supervisor, [guitar, good]).
Musician Wanda Perlstein, playing the guitar entered the room
{ok,<0.698.0>}
Run Code Online (Sandbox Code Playgroud)

我注意到所有工人都有相同的Child spec Id: jam_musician

你知道其他类型的工作者必须拥有唯一的子ID,对吧?

use*_*836 5

很可能你写了子进程的start_link函数(我假设它是gen_server):

start_link() ->
    gen_server:start_link({local,Name}, ?MODULE, [], []).
Run Code Online (Sandbox Code Playgroud)

这不仅调用init/1函数,还使用atom Name注册进程.

因此,任何新的子开始在第二时刻将尝试使用已经采取的第一个孩子的名字Erlang的节点内注册.

为了避免这种名称冲突,你应该使用类似的东西:

start_link() ->
    gen_server:start_link(?MODULE, [], []).
Run Code Online (Sandbox Code Playgroud)

所以没有孩子会有一个注册名称,你就不会发生冲突.

如果你真的需要注册每个孩子,一个选项可能包括使用gproc.

  • 这将产生错误,而不是'already_started`返回.如果你使用**而不是'simple_one_for_one`主管执行`restart_child/2`并且你尝试启动已经启动的id,那么你将****只获得一个`already_started`.您无法通过忽略id的`simple_one_for_one`主管来获取它. (2认同)

Isa*_*sac 5

simple_one_for_one监督者的子规范标识符将是相同的,因为只有一种子类型和许多这种类型的子实例(工人)。

supervisor行为文档

请注意,当重新启动策略为 时simple_one_for_one,子规范列表必须是只有一个子规范的列表。(忽略子规范标识符。)然后在初始化阶段不会启动任何子进程,但假定所有子进程都使用 动态启动start_child/2