2014-04-01 73 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