2014-04-01 44 views
0

我必须实现erlang gen_server进程,这些进程几个小时都在运行。但超时后gen_server进程应该被终止。这些过程是动态启动的,因此使用动态监督。这个想法是在进程init上使用timer:apply_after()。所以gen_server进程初始化看起来像Erlang gen_server进程超时

init(Time) -> 
    timer:apply_after(Time, my_supervisor, kill_child, [self()]), 
    % do other init things 
    ok. 

我有点新的二郎神所以,问题是做这种做法是罚款,它也有一些缺点?有更好的解决方案吗?

谢谢!

回答

2

你可能要考虑使用二郎:send_after/3与handle_info对消息作出反应在gen_server:

使用Erlang的创建定时器:send_after/3和Erlang:START_TIMER/3是 更高于使用定时器 模块提供的定时器。定时器模块使用单独的进程来管理定时器,如果许多进程创建 并频繁取消定时器(特别是在使用SMP模拟器时),那么该进程可能很容易变得过载。

定时器模块中不管理定时器的功能(如 定时器:tc/3或定时器:睡眠/ 1)不会调用定时器服务器进程,因此 因此是无害的。

http://www.erlang.org/doc/efficiency_guide/commoncaveats.html

+0

谢谢你的回复。但是,在处理消息时,我遇到了终止进程的问题。所以问题是当进程死了时它仍然处于主管状态,并且不可能用相同的名称启动进程,因为主管说{error,already_present},有没有解决方法?再次感谢! –

3

我会做不同的事情:

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

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

这样,过程正常关闭本身,而不需要管理者将其杀死。更好的是,你可以在主管中声明孩子为transient,所以它不会重新启动。

+0

感谢您的回答。此解决方案正常工作。但是由于这个过程是由主管动态创建的,所以它仍然处于主管状态,并且不可能创建一个和以前一样名字的进程 –

+0

@KonstantinShamko你如何创建你的主管? – BlackMamba

+0

@BlackMamba这是spervisor 的初始化'的init([]) - > MAXRESTARTS = 5, MAXTIME = 10,{ 确定,{{one_for_one,MAXRESTARTS,MAXTIME},[ ]}}。 ' –

0

你可以试试这个代码:进程worker1每秒关机一次,进程worker2每隔两秒关机一次。 您只需加载两个光束,然后在erl外壳中运行super:start_link(). super:main().

这是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_server:

-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}. 
+0

但是,如果我像 supervisor:start_child(Sup,{some_name,{MFA},...})那样动态地启动工作人员,当这名工人在超时后死亡时,我无法启动具有some_name名称的另一名工人,因为它并未被监督员的状态删除。这就是问题 –

+0

我修改了我的代码。你可以看到它,当工作人员去世时,主管将会开始工作,你不需要自己重新启动它。 – BlackMamba