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

时间:2018-02-22 15:48:43

标签: erlang erlang-shell

这是一个示例跟踪,我可以在同一个Pid上调用let result = String(myText.enumerated().map { guard (2...3).contains($0.offset) else { return $0.element } switch $0.element { case "I": return "1" case "Z": return "2" default: return $0.element } }) print(result)

let result = String(myText.enumerated().map {
    switch $0.element {
    case "I" where (2...3).contains($0.offset):
        return "1"
    case "Z" where (2...3).contains($0.offset):
        return "2"
    default:
        return $0.element
    }
})

指令#4和#5返回的表达式与#3不同,这意味着可以在当前进程和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 个答案:

答案 0 :(得分:5)

想象一下,您使用的第三方库(基本上是OTP *:call/*函数的功能):

call(Pid, Request) ->
    call(Pid, Request, ?DEFAULT_TIMEOUT).

call(Pid, Request, Timeout) ->
    MRef = erlang:monitor(process, Pid),
    Pid ! {call, self(), MRef, Request},
    receive
      {answer, MRef, Result} ->
        erlang:demonitor(Mref, [flush]),
        {ok, Result};
      {'DOWN', MRef, _, _, Info} ->
        {error, Info}
    after Timeout ->
        erlang:demonitor(MRef, [flush]),
        {error, timeout}
    end.

然后您在代码中使用它,您将监视相同的进程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是由经验丰富的人制作的。可维护性是关键所在。