“我有多少链接?”,问一个Erlang进程

时间:2012-12-10 12:42:59

标签: multithreading process erlang

Erlang中的进程会调用link/1spawn_link来创建与其他进程的链接。在我最近的一个应用程序中,我很想知道一个进程是否可以在给定的实例中知道它与其链接的其他进程的数量。这可能吗 ?他们是BIF吗?

然后,当链接进程终止时,我猜如果可以知道链接进程的数量,这个数字将由运行时系统自动递减。这种机制在处理Erlang并发程序中的Parent-Child关系时非常理想,即使是在不涉及supervisors的简单关系中也是如此。

嗯,Erlang进程是否有可能通过BIF知道out-of-the-box,链接到它的进程数量,这样每当链接进程终止时,该值会自动递减under-the-hood :?)


要稍微扩展这个问题,请考虑gen_server,它将通过handle_info处理数千条消息。在这一部分中,它的工作是dispatch个子进程在它进入时立即处理任务。这样做的目的是确保server loop立即返回以接收下一个请求。现在,子进程异步处理任务,并在它死亡之前将回复发送回请求者。在继续之前,请参阅此question及其答案。

现在,如果,对于gen_server产生的每个子进程,都会创建一个链接,并且我想将此链接用作计数器。我知道,我知道,每个人都会像“为什么不使用gen_server State,携带说,一个计数器,然后相应地增加或减少它?”:)在gen_server的某个地方,我有:

handle_info({Sender,Task},State)->
    spawn_link(?MODULE,child,[Sender,Task]),
    %%  At this point, the number of links to the gen_server is incremented
    %%  by the run-time system
    {noreply,State};
handle_info( _ ,State) -> {noreply,State}.

孩子继续这样做:

child(Sender,Task)->
    Result = (catch execute_task(Task)),
    Sender ! Result,
    ok. %% At this point the child process exits, 
        %% and i expect the link value to be decremented

最后,gen_server有一个暴露的调用:

get_no_of_links()-> gen_server:call(?MODULE,links).
handle_call(links, _ ,State)->
    %% BIF to get number of instantaneous links expected here
    Links = erlang:get_links(), %% This is fake, do not do it at home :)
    {reply,Links,State};
handle_call(_ , _ ,State)-> {reply,ok,State}.

现在,有人可能会问自己,真的,为什么有人想要这样做?

通常,可以在gen_server状态中创建一个整数然后我们自己做,或者至少使gen_server handle_info类型为{'EXIT',ChildPid,_Reason},然后服务器会相应地执行操作。我的想法是,如果有可能知道链接的数量,我会用它来知道(在给定的时刻),有多少子进程仍在忙着工作,这反过来可能实际上有助于预测服务器负载。

2 个答案:

答案 0 :(得分:8)

来自process_info的手册:

  

{links,Pids}:                     Pids是一个pid列表,其中包含进程的进程                     有一个链接

3> process_info(self(), links).
{links,[<0.26.0>]}
4> spawn_link(fun() -> timer:sleep(100000) end).
<0.38.0>
5> process_info(self(), links).                 
{links,[<0.26.0>,<0.38.0>]}

我想它可以用来计算链接进程的数量

答案 1 :(得分:2)

您的流程应该运行process_flag(trap_exit, true)并收听{'EXIT', Pid, Reason}形式的消息,该消息将在链接进程退出时到达。如果您没有捕获退出,则默认行为将是链接进程在链接的另一侧退出时退出。

至于在流程添加链接时进行监听,您可以使用case process_info(self(), links) of {links, L} -> length(L) endlength(element(2, process_info(self(), links)),但必须定期重新运行此流程,因为无论何时链接都无法通知您的流程已添加。

遵循OTP指南的流程永远不需要知道有多少进程链接到它。