【问题标题】:How to spawn a variable number of gen_servers in Erlang如何在 Erlang 中生成可变数量的 gen_servers
【发布时间】:2016-06-22 17:43:00
【问题描述】:

目前我正在使用lists:foreachspawn_link 为项目启动可变数量的“工人”,即在启动时确定的工人数量。我希望每个工作人员都是一个 gen_server,这样我就可以在其中调用异步或同步消息(gen_server:cast 等)这可能吗?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    是的,这是可能的。

    您可以使用 simple_one_for_onehttp://erlang.org/doc/man/supervisor.html#start_child-2

    一个简化的 one_for_one 主管,其中所有子进程都是 动态添加相同进程类型的实例。

    这是一个代码示例: master.erl 是主管:

    -module(master).
    
    -behaviour(supervisor).
    
    %% API
    -export([start_link/0]).
    
    %% Supervisor callbacks
    -export([init/1]).
    
    -define(SERVER, ?MODULE).
    
    start_link() ->
        supervisor:start_link({local, ?SERVER}, ?MODULE, []).
    
    init([]) ->
        RestartStrategy = simple_one_for_one,
        MaxRestarts = 1000,
        MaxSecondsBetweenRestarts = 3600,
    
        SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
    
        Restart = permanent,
        Shutdown = 2000,
        Type = worker,
    
        AChild = {'worker', {'worker', start_link, []},
              Restart, Shutdown, Type, ['worker']},
    
        {ok, {SupFlags, [AChild]}}.
    

    worker.erl 是童工:

    -module(worker).
    
    -behaviour(gen_server).
    
    %% API
    -export([start_link/0]).
    -export([start_link/1]).
    
    %% gen_server callbacks
    -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).
    
    -define(SERVER, ?MODULE). 
    
    -record(state, {}).
    
    start_link() ->
        gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
    start_link(I) ->
        ServerName = lists:flatten(io_lib:format("~p~p", [?SERVER, I])),
        io:format("I am ~p~n", [list_to_atom(ServerName)]),
        gen_server:start_link({local, list_to_atom(ServerName)}, ?MODULE, [], []).
    
    init([]) ->
        {ok, #state{}}.
    
    
    handle_call(_Request, _From, State) ->
        Reply = ok,
        {reply, Reply, State}.
    
    handle_cast(calc, State) ->
         io:format("result 2+2=4~n"),
         {noreply, State};
    handle_cast(calcbad, State) ->
         io:format("result 1/0~n"),
         1 / 0,
         {noreply, State};
    handle_cast(_Msg, State) ->
        {noreply, State}.
    
    handle_info(_Info, State) ->
        {noreply, State}.
    
    
    terminate(_Reason, _State) ->
        ok.
    
    code_change(_OldVsn, State, _Extra) ->
        {ok, State}.
    

    在 erlang shell 中:

    22> master:start_link().                                                               
    {ok,<0.2475.0>}
    23> lists:map(fun(X) -> supervisor:start_child(master, [X]) end, lists:seq(1, 10)).
    

    【讨论】:

    • 看起来不错,但我怎样才能让主管让孩子们开始跑步?
    【解决方案2】:

    没有什么可以阻止您调用my_worker:start_link 而不是spawn_link

    在工人中

    -module(my_worker).
    
    -behaviour(gen_server).
    
    %% API
    
    -export([start_link/1]).
    
    %% gen_server callbacks
    
    -export([init/1, ...]).
    
    %% API
    
    start_link(Arg) ->
        gen_server:start_link(?MODULE, Arg, []).
    
    %% gen_server callbacks
    
    init(Arg) ->
        ...
    

    然后你就可以启动它了

    [ {ok, _Pid} = my_worker:start_link(Arg) || Arg <- Args ].
    

    如果您想将他们置于主管之下:

    -module(my_sup).
    
    -behaviour(supervisor).
    
    %% API
    
    -export([start_link/1]).
    
    %% supervisor callbacks
    
    -export([init/1]).
    
    %% API
    
    start_link(Argg) ->
        gen_server:start_link(?MODULE, Args).
    
    %% supervisor callbacks
    
    init(Args) ->
        Sup_flags = #{strategy => one_for_one, intensity => 1, period => 5},
        Child_specs = [ #{id => Id, start => MFA}
            || {Id, {_M, _F, _A} = MFA} <- Args ],
        {ok, {Sup_flags, Child_specs}}.
    

    您可以从application:get_env/1,2,3 或数据库或其他任何地方读取他们的配置。之后您可以使用supervisor:start_child/2 启动它们。您可以使用simple_one_for_one 等。这只是一个过程。

    【讨论】:

      猜你喜欢
      • 2017-07-12
      • 1970-01-01
      • 2011-06-19
      • 2011-04-18
      • 2021-11-13
      • 1970-01-01
      • 2012-12-06
      • 2019-06-04
      • 1970-01-01
      相关资源
      最近更新 更多