3

Erlang 中的进程将调用link/1spawn_link创建与另一个进程的链接。在我正在研究的最近的一个应用程序中,我很好奇一个进程是否有可能在给定的实例中知道它所链接的其他进程的数量。这可能吗 ?他们是 BIF 吗?

然后,当一个链接进程死亡时,我猜如果有可能知道链接进程的数量,这个数字将由运行时系统自动递减。这种机制在处理Parent-ChildErlang 并发程序中的关系时是理想的,即使是在不涉及supervisors.

那么,Erlang 进程是否有out-of-the-box可能通过 BIF 知道链接到它的进程的数量,这样每当一个链接的进程死亡时,这个值就会自动递减under-the-hood:)?


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

现在,如果为每个由 gen_server 生成的子进程创建一个链接,我想使用这个链接作为计数器。我知道,我知道,每个人都会像“为什么不使用 gen_serverState,携带一个计数器,然后相应地增加或减少它?" :) 在 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},然后服务器会相应地采取行动。我的想法是,如果可以知道链接的数量,我会用它来知道(在给定的时间),有多少子进程仍在忙于工作,这反过来实际上可能有助于预测服务器负载。

4

2 回答 2

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

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

于 2012-12-10T12:56:58.033 回答
1

您的进程应该运行process_flag(trap_exit, true)并侦听表单的消息,这些消息{'EXIT', Pid, Reason}将在链接的进程退出时到达。如果您不捕获退出,则默认行为将是您的链接进程在链接的另一端退出时退出。

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

遵循 OTP 指南的流程永远不需要知道有多少流程与其相关联。

于 2012-12-10T13:13:59.597 回答