首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >存储主管子PID

问存储主管子PID
EN

Stack Overflow用户
提问于 2011-11-14 18:36:14
回答 2查看 2.7K关注 0票数 4

我是Erlang初学者,正在尝试实现我的第一个Erlang应用程序。它是一个网络监控工具,应该对指定的主机执行ping请求。实际上发送ICMP不是目的,我更感兴趣的是应用程序结构。目前我有monitor_app,monitor_sup (根),pinger_sup和pinger (工人)。这是pinger_sup:

代码语言:javascript
复制
-module(pinger_sup).
-behaviour(supervisor).
-export([start_link/0, start_child/1, stop_child/1]).
-export([init/1]).

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

start_child(Ip) ->
    {ok, Pid} = supervisor:start_child(?MODULE, Ip),
    put(Pid, Ip),
    {ok, Pid}.

stop_child(Ip) ->
    Children = get_keys(Ip),
    lists:foreach(fun(Pid) ->
            pinger:stop(Pid)
        end,
        Children).

init(_Args) ->
    Pinger = {pinger, {pinger, start_link, []},
        transient, 2000, worker, [pinger]},
    Children = [Pinger],
    RestartStrategy = {simple_one_for_one, 4, 3600},
    {ok, {RestartStrategy, Children}}.

平淡无奇地:

代码语言:javascript
复制
-module(pinger).
-behaviour(gen_server).
-export([start_link/1, stop/1, stop_ping/1, ping/1, ping/2]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(PING_INTERVAL, 5000).

start_link(Ip) ->
    gen_server:start_link(?MODULE, Ip, []).

stop(Pid) ->
    gen_server:cast(Pid, stop).

stop_ping(Ip) ->
    pinger_sup:stop_child(Ip).

ping(Ip) ->
    pinger_sup:start_child(Ip).

ping(_Ip, 0) ->
    ok;
ping(Ip, NProc) ->
    ping(Ip),
    ping(Ip, NProc - 1).

init(Ip) ->
    erlang:send_after(1000, self(), do_ping),
    {ok, Ip}.

handle_call(_Request, _From, State) ->
    {noreply, State}.

handle_cast(stop, State) ->
    io:format("~p is stopping~n", [State]),
    {stop, normal, State}.

handle_info(do_ping, State) ->
    io:format("pinging ~p~n", [State]),
    erlang:send_after(?PING_INTERVAL, self(), do_ping),
    {noreply, State};
handle_info(Info, State) ->
    io:format("Unknown message: ~p~n", [Info]),
    {noreply, State}.

terminate(_Reason, State) ->
    io:format("~p was terminated~n", [State]),
    ok.

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

它缺乏评论,但我认为它是非常简单和熟悉的任何Erlang开发人员。关于这个代码,我没有几个问题:

( 1) *erlang:send_after*在init中是一个很好的解决方案吗?什么是最好的实践,如果我需要过程,开始做这项工作,它是在没有从外部触发他的功能的情况下产生的?

2)目前我使用ping启动ping:ping(“127.0.0.1”)。命令。pinger模块要求pinger_sup启动子进程。在这个过程开始后,我想停止它。最好的方法是什么?我应该用sup终止它,还是我应该给他发送停止命令?如何存储进程PID?目前,我使用过程字典,但是在实现它之后,我意识到该字典实际上不属于sup (它是一个shell字典或任何其他stop_child调用者)。如果我使用ETS并终止sup,这些死进程PID会永远留在ETS中导致某种内存泄漏吗?

我很感谢你的回答和代码评论。

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-11-16 14:55:58

( 1) erlang:send_after在init中是一个很好的解决方案吗?

不是的。

什么是最好的实践,如果我需要过程,开始做这项工作,它是在没有从外部触发他的功能的情况下产生的?

见这里。将超时设置为0,然后执行:

代码语言:javascript
复制
handle_info(timeout, State) ->
    whatever_you_wish_to_do_as soon_as_server_starts,
    {noreply, State}.

零超时意味着服务器在处理任何其他调用/强制转换之前,会在它完成时立即发送“超时值”信息。

另外,请参见定时器模块。不要重述调用send_after in handle_info(do_ping,State),只需启动计时器并告诉他向您发送"do_ping“每个?PING_INTERVAL。

2)目前我使用ping启动ping:ping(“127.0.0.1”)。命令。pinger模块要求pinger_sup启动子进程。在这个过程开始后,我想停止它。最好的方法是什么?我应该用sup终止它,还是我应该给他发送停止命令?

你应该给他发个停止命令。如果gen_server可以自己完成,为什么使用主管来杀死gen_server?:-)

如何存储进程PID?目前,我使用过程字典,但是在实现它之后,我意识到该字典实际上不属于sup (它是一个shell字典或任何其他stop_child调用者)。如果我使用ETS并终止sup,这些死进程PID会永远留在ETS中导致某种内存泄漏吗?

一旦所有者进程终止,ETS表就会被销毁。所以那里没有内存泄漏。

但是,以这样的方式存储PID并不是“erlang方式”。相反,我建议制作一棵主管树。我建议pinger_sup启动一个管理器来处理给定的IP,而不是将所有pinger员工都放在这个IP下,然后记住哪个工作人员执行哪个IP。然后这个主管开始需要多少工人。

现在,当你想停止敲击某些IP的时候,你只要杀死那个IP的主管,他就会自动杀死他的孩子。

你怎么知道哪个主管处理哪个IP?那么,把IP放在主管的名字里:-)当产生处理IP的主管时,做如下的事情:

代码语言:javascript
复制
-module(pinger_ip_sup).

start_link(Ip) ->
    supervisor:start_link({global, {?MODULE, Ip}}, ?MODULE, []).

然后,当你想停止敲击一个叶问的时候,你只要用{pinger_ip_sup,Ip }这个名字杀死主管,他就会杀了他的孩子:-)

关于评论的编辑:

如果您希望处理产生超时的错误,您可以保留一个状态变量,它将告诉您是由init产生的超时,还是由错误产生的超时。例如:

代码语言:javascript
复制
-record(pinger_state, {ip, initialized}).

init(Ip) ->
    State = #pinger_state{ip = Ip, initialized = false}.
    {ok, State, 0}.

handle_info(timeout, State#pinger_state{initialized = false}) ->
    whatever_you_wish_to_do_as soon_as_server_starts,
    New_state = State#pinger_state{initialized = true}.
    {noreply, New_state}.

handle_info(timeout, State#pinger_state{initialized = true}) ->
    error_handling,
    {noreply, State}.

这样,您就可以使用此机制并处理超时错误。但是,这里真正的问题是:您期望超时错误吗?

至于计时器:是的,计时器有一些开销,以防您计划执行DDOS攻击或诸如此类的事情:-D -如果您不打算像疯狂地创建和取消计时器,那么使用计时器模块就更优雅了。这是你必须做出的一个设计选择:你想要一个干净而优雅的代码,还是当其他所有的代码都中断时,代码能够站立起来。我怀疑你需要后者。但是你最清楚。

票数 7
EN

Stack Overflow用户

发布于 2013-10-12 11:32:44

我想你需要什么“存储监督子pid”是二郎:注册(原子,pid)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8126391

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档