gpt4 book ai didi

erlang - 存储主 pipe PID

转载 作者:行者123 更新时间:2023-12-04 23:28:49 25 4
gpt4 key购买 nike

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

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

和 pinger 本身:
-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) init 中的 *erlang:send_after* 是一个好的解决方案吗?如果我需要进程立即开始工作而不从外部触发他的功能,那么最佳实践是什么?

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

我感谢任何答案和代码注释。

谢谢!

最佳答案

1) Is erlang:send_after in init a good solution?



不。

What is the best practise if I need process start doing the job immidiately it was spawned without triggering his functions from outside?



here .将超时设置为 0,然后执行:
handle_info(timeout, State) ->
whatever_you_wish_to_do_as soon_as_server_starts,
{noreply, State}.

零超时意味着服务器将在完成初始化后立即向自己发送“超时”信息,然后再处理任何其他调用/强制转换。

另见 timer module .与其在 handle_info(do_ping, State) 中递归调用 send_after,不如启动计时器并告诉他每隔 ?PING_INTERVAL 向您发送“do_ping”。

2) Currently I initiate ping using pinger:ping("127.0.0.1"). command. pinger module ask pinger_sup to start child process. After the process was started I want to stop it. What is the preferable way of doing it? Should I terminate it by sup or should I send him stop command?



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

How should I store the process PID? Currently I use process dictionary but after implementing it I've realized that the dictionary actually doesn't belong to sup (it's a shell dictionary or any other stop_child caller). In case I use ETS and the sup was terminated would these dead process PIDs stay in ETS forever causing kind of memory leak?



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

但是,以您的方式存储 PID 不是“erlang 方式”。相反,我建议制作一个主管树。我建议 pinger_sup 启动一个处理给定 IP 的主管,而不是将所有 pinger 工作人员放在 pinger_sup 下然后记住哪个工作人员 ping 哪个 IP。然后这个主管启动所需数量的 worker 。

现在,当您希望停止 ping 某个 IP 时,您只需杀死该 IP 的主管,他会自动杀死他的 child 。

你怎么知道哪个主管处理哪个 IP?好吧,将 IP 放在主管的名字中 :-) 当生成处理 IP 的主管时,请执行以下操作:
-module(pinger_ip_sup).

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

然后,当您希望停止 ping 一个 Ip 时,您只需用名称 {global, {pinger_ip_sup, Ip}} 杀死主管,他会杀死他的 child :-)

编辑有关评论:

如果您希望处理产生超时的错误,您可以保留一个状态变量,它会告诉您是由 init 产生的超时还是由错误产生的超时。例如:
-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 如果您不打算疯狂地创建和取消计时器,那么使用计时器模块会更加优雅。这是您必须做出的设计选择:您想要一个干净优雅的代码,还是可以在其他一切都中断时仍然存在的代码。我怀疑你需要后者。但是,你最清楚。

关于erlang - 存储主 pipe PID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8126391/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com