Erlang gen_服务器进程超时

Erlang gen_服务器进程超时,erlang,timeout,gen-server,Erlang,Timeout,Gen Server,我必须实现erlang gen_服务器进程,这些进程可以运行数小时。但超时后,gen_服务器进程应该被终止。这些过程是动态启动的,因此使用了动态监控。其思想是在进程init上使用timer:apply_after()。gen_服务器进程的init如下所示 init(Time) -> timer:apply_after(Time, my_supervisor, kill_child, [self()]), % do other init things ok. 我对erl

我必须实现erlang gen_服务器进程,这些进程可以运行数小时。但超时后,gen_服务器进程应该被终止。这些过程是动态启动的,因此使用了动态监控。其思想是在进程init上使用timer:apply_after()。gen_服务器进程的init如下所示

init(Time) -> 
   timer:apply_after(Time, my_supervisor, kill_child, [self()]),
   % do other init things
   ok.
我对erlang有点陌生,所以问题是这种方法是好的还是有一些缺点?有更好的解决办法吗


谢谢

> P>您可能想考虑使用Erlang:sEntId/Stand 3,并用HANDLYNOFION: < /P>对GeNEX服务器中的消息作出反应。 使用erlang:send\u after/3和erlang:start\u timer/3创建计时器 比使用计时器提供的计时器效率更高 模块。定时器模块使用单独的过程来管理定时器, 如果许多进程创建 并经常取消计时器(尤其是在使用SMP仿真器时)

计时器模块中不管理计时器的功能(例如 计时器:tc/3或计时器:sleep/1),不要调用计时器服务器进程和 因此它们是无害的


您可能想考虑使用Erlang:sEntId/Stand 3,并用HANDLYNFION: < /P>对GeNEX服务器中的消息作出反应。 使用erlang:send\u after/3和erlang:start\u timer/3创建计时器 比使用计时器提供的计时器效率更高 模块。定时器模块使用单独的过程来管理定时器, 如果许多进程创建 并经常取消计时器(尤其是在使用SMP仿真器时)

计时器模块中不管理计时器的功能(例如 计时器:tc/3或计时器:sleep/1),不要调用计时器服务器进程和 因此它们是无害的


我会做一些不同的事情:

init([]) ->
    erlang:send_after(Time, self(), timeout_shutdown),
    {ok, #state{}}.

handle_info(timeout_shutdown, State) ->
    {stop, normal, State};
...

通过这种方式,进程会自动关闭,而无需主管终止它。更好的方法是,您可以在supervisor中将子项声明为瞬态,这样它就不会重新启动。

我会做一些不同的事情:

init([]) ->
    erlang:send_after(Time, self(), timeout_shutdown),
    {ok, #state{}}.

handle_info(timeout_shutdown, State) ->
    {stop, normal, State};
...

通过这种方式,进程会自动关闭,而无需主管终止它。更好的方法是,您可以在supervisor中将子进程声明为瞬态,这样它就不会重新启动。

您可以尝试以下代码:进程
worker1
每秒关闭一次,进程
worker2
每两秒关闭一次。 您只需加载两个梁,然后运行
super:start\u link()。super:main()。
在erl shell中

这是supervosor:

-module(super).
-behaviour(supervisor).
%% API
-export([start_link/0]).
-export([stop/0]).
-export([main/]).
%% 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]}}.

main() ->
    add_worker(worker1, 1000),
    add_worker(worker2, 2000).

add_worker(WorkerName, Time) when is_atom(WorkerName)->
    supervisor:start_child(?SERVER, [WorkerName, Time]).
stop() ->
    exit(whereis(?SERVER), shutdown).
这是gen_服务器:

-module(worker).
-behaviour(gen_server).
%% API
-export([start_link/2]).

%% 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(WorkerName, Time) ->
    io:format("server: ~p start!~n", [WorkerName]),
    gen_server:start_link({local, WorkerName}, ?MODULE, [WorkerName, Time], []).

init([WorkerName, Time]) ->
    erlang:send_after(Time, self(), {WorkerName, timeout_shutdown}),
    {ok, #state{}}.


handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.


handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({WorkerName, timeout_shutdown}, State) ->
    io:format("server: ~p timeout_shutdown!~n", [WorkerName]),
    {stop, normal, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

您可以尝试以下代码:进程
worker1
每秒钟关闭一次,进程
worker2
每两秒钟关闭一次。 您只需加载两个梁,然后运行
super:start\u link()。super:main()。
在erl shell中

这是supervosor:

-module(super).
-behaviour(supervisor).
%% API
-export([start_link/0]).
-export([stop/0]).
-export([main/]).
%% 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]}}.

main() ->
    add_worker(worker1, 1000),
    add_worker(worker2, 2000).

add_worker(WorkerName, Time) when is_atom(WorkerName)->
    supervisor:start_child(?SERVER, [WorkerName, Time]).
stop() ->
    exit(whereis(?SERVER), shutdown).
这是gen_服务器:

-module(worker).
-behaviour(gen_server).
%% API
-export([start_link/2]).

%% 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(WorkerName, Time) ->
    io:format("server: ~p start!~n", [WorkerName]),
    gen_server:start_link({local, WorkerName}, ?MODULE, [WorkerName, Time], []).

init([WorkerName, Time]) ->
    erlang:send_after(Time, self(), {WorkerName, timeout_shutdown}),
    {ok, #state{}}.


handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.


handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({WorkerName, timeout_shutdown}, State) ->
    io:format("server: ~p timeout_shutdown!~n", [WorkerName]),
    {stop, normal, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

谢谢你的回复。但在通过消息处理时,我遇到了进程终止的问题。所以问题是,当进程死亡时,它仍然处于主管状态,不可能以相同的名称启动进程,因为主管说{error,ready_present},有什么解决方法吗?再次感谢!谢谢你的回复。但在通过消息处理时,我遇到了进程终止的问题。所以问题是,当进程死亡时,它仍然处于主管状态,不可能以相同的名称启动进程,因为主管说{error,ready_present},有什么解决方法吗?再次感谢!谢谢你的回答。这个解决方案很好用。但由于流程是由主管动态创建的,因此它仍处于主管的状态,因此不可能创建与主管同名的流程before@KonstantinShamko如何创建您的主管?@BlackMamba这是spervisor的init
init([])->maxsrestarts=5,MaxTime=10,{好的,{一对一,maxsrestarts,MaxTime},[     ]}}.
也许您需要一个简单的\u-one \u作为\u-one主管?谢谢您的回答。此解决方案运行良好。但由于流程是由主管动态创建的,因此它仍处于主管状态,因此无法创建与主管同名的流程before@KonstantinShamko你如何创建你的主管?@BlackMamba这是spe的初始化rvisor
init([])->maxrestart=5,MaxTime=10,{ok,{one_代表one,maxrestart,MaxTime},[]}。
也许您需要一个简单的one_代表one主管?但如果我像主管那样动态启动worker:start_child(Sup,{some_name,{MFA},…})。当此工作程序在超时后死亡时,我无法启动另一个具有某个名称的工作程序,因为它未被删除为主管的状态。这就是问题。我已修改了我的代码。您可以看到,当工作程序死亡时,主管将重新启动它,您无需自行重新启动。但如果我像主管一样动态启动工作程序:start_child(Sup,{some_name,{MFA},…})。当此工作进程在超时后死亡时,我无法启动另一个具有某个_name名称的工作进程,因为它未针对主管的状态删除。这就是问题。我已修改了我的代码。您可以看到,当该工作进程死亡时,主管将重新启动它,您无需自行重新启动它。