为什么可以在Erlang中为同一进程创建多个监视器引用?

为什么可以在Erlang中为同一进程创建多个监视器引用?,erlang,erlang-shell,Erlang,Erlang Shell,下面是一个示例跟踪,我可以在同一个Pid上调用erlang:monitor/2: 1> Loop = fun F() -> F() end. #Fun<erl_eval.30.99386804> 2> Pid = spawn(Loop). <0.71.0> 3> erlang:monitor(process, Pid). #Ref<0.2485499597.1470627842.126937> 4> erlang:monitor(

下面是一个示例跟踪,我可以在同一个Pid上调用
erlang:monitor/2

1> Loop = fun F() -> F() end.
#Fun<erl_eval.30.99386804>
2> Pid = spawn(Loop).
<0.71.0>
3> erlang:monitor(process, Pid).
#Ref<0.2485499597.1470627842.126937>
4> erlang:monitor(process, Pid).
#Ref<0.2485499597.1470627842.126942>
5> erlang:monitor(process, Pid).
#Ref<0.2485499597.1470627842.126947>
1>循环=fun F()->F()结束。
#乐趣
2> Pid=繁殖(循环)。
3> erlang:监视器(进程,Pid)。
#参考号
4> erlang:监视器(进程,Pid)。
#参考号
5> erlang:监视器(进程,Pid)。
#参考号
指令#4和#5返回的表达式与#3不同,这意味着可以在当前进程和
Pid
之间创建多个监视器引用。是否存在需要或使用多个监视器引用到同一流程的实际情况


我希望它返回相同的引用(返回一个新的引用可能意味着旧的引用失败/崩溃),遵循
link/1

中存在的相同逻辑假设您使用第三方库来实现这一点(基本上是OTP
*:call/*
函数所做的):

然后在代码中使用它,监视相同的进程
Pid
,然后调用函数
call/2,3

my_fun1(Service) ->
    MRef = erlang:monitor(process, Service),
    ok = check_if_service_runs(MRef),
    my_fun2(Service),
    mind_my_stuf(),
    ok = check_if_service_runs(MRef),
    erlang:demonitor(MRef, [flush]),
    return_some_result().

check_if_service_runs(MRef) ->
    receive
      {'DOWN', MRef, _, _, Info} -> {down, Info}
    after 0 -> ok
    end.

my_fun2(S) -> my_fun3(S).

% and a many layers of other stuff and modules
my_fun3(S) -> call(S, hello).

如果
erlang:monitor/2,3
总是返回相同的引用,如果
erlang:demonitor/1,2
删除以前的监视器,那将是多么令人讨厌的意外。这将是一个丑陋和无法解决的错误的来源。您应该开始认为有库、其他进程,您的代码是一个庞大系统的一部分,而Erlang是由经验丰富的人精心设计的。可维护性是这里的关键。

在开始研究OTP后,我不得不承认我没有想到这一点。然而,cast不是比call更合适的例子吗?因为它是异步的,并且可能有多个挂起的请求?我认为执行
call/3
实现的进程一次只能执行一个操作,因此只需要一个监控引用。这是真的吗?否则,我想我肯定知道它是多么有用。非常感谢你的回答。@goncalotomas:你还是没有得到答案。问题不在于它是调用还是强制转换,而在于它们之外的代码。您可以将监视器保存在代码或其他第三方库中。在一种具有不变性的函数式语言中,可以自定义使用不透明状态、回调等创建库,这些状态可以包含
MRef
s并根据需要保留它。你必须想得更大些。有一个最大的函数式语言商业项目ADX301,它是由Erlang设计的,用于处理200万行代码。“你必须想得更大一些。”goncalotomas:我添加了更多的代码,希望能帮助你更好地理解这个问题。它是非常人工的,但我希望它能有所帮助。我想我现在看到了它-可能有几层代码
self()。我想这就是原因,谢谢!您最后添加的代码帮助很大。
my_fun1(Service) ->
    MRef = erlang:monitor(process, Service),
    ok = check_if_service_runs(MRef),
    my_fun2(Service),
    mind_my_stuf(),
    ok = check_if_service_runs(MRef),
    erlang:demonitor(MRef, [flush]),
    return_some_result().

check_if_service_runs(MRef) ->
    receive
      {'DOWN', MRef, _, _, Info} -> {down, Info}
    after 0 -> ok
    end.

my_fun2(S) -> my_fun3(S).

% and a many layers of other stuff and modules
my_fun3(S) -> call(S, hello).