0

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

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

我对 erlang 有点陌生,所以问题是这种方法是好的还是有一些缺点?有更好的解决方案吗?

谢谢!

4

3 回答 3

3

我会做一些不同的事情:

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

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

这样,进程就会优雅地自行关闭,而不需要主管杀死它。更好的是,您可以将孩子声明为transient主管,因此它不会重新启动。

于 2014-04-01T20:27:06.270 回答
2

您可能需要考虑使用 erlang:send_after/3 并使用 handle_info 对 gen_server 中的消息做出反应:

使用 erlang:send_after/3 和 erlang:start_timer/3 创建定时器比使用 timer 模块提供的定时器要高效得多。计时器模块使用一个单独的进程来管理计时器,如果许多进程频繁地创建和取消计时器(尤其是在使用 SMP 仿真器时),该进程很容易过载。

timer 模块中不管理定时器的函数(例如 timer:tc/3 或 timer:sleep/1)不调用 timer-server 进程,因此是无害的。

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

于 2014-04-01T17:01:14.570 回答
0

你可以试试这个代码:进程worker1每秒关闭一次,进程worker2每两秒关闭一次。您只需要加载两个梁,并super:start_link(). super:main().在 erl shell 中运行。

这是超级用户:

-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}.
于 2014-04-02T09:19:42.753 回答