了解你的一些Erlang书籍如下code。为什么这本书有时只使用超时,有时同时使用监视器和超时?在下面是什么需要监视器,因为超时将有效地检测进程是否已关闭?
%% Synchronous call
order_cat(Pid, Name, Color, Description) ->
Ref = erlang:monitor(process, Pid),
Pid ! {self(), Ref, {order, Name, Color, Description}},
receive
{Ref, Cat} ->
erlang:demonitor(Ref, [flush]),
Cat;
{'DOWN', Ref, process, Pid, Reason} ->
erlang:error(Reason)
after 5000 ->
erlang:error(timeout)
end.
同时比较以下add_event
不使用监视器但subscribe
执行
subscribe(Pid) ->
Ref = erlang:monitor(process, whereis(?MODULE)),
?MODULE ! {self(), Ref, {subscribe, Pid}},
receive
{Ref, ok} ->
{ok, Ref};
{'DOWN', Ref, process, _Pid, Reason} ->
{error, Reason}
after 5000 ->
{error, timeout}
end.
add_event(Name, Description, TimeOut) ->
Ref = make_ref(),
?MODULE ! {self(), Ref, {add, Name, Description, TimeOut}},
receive
{Ref, Msg} -> Msg
after 5000 ->
{error, timeout}
end.
答案 0 :(得分:4)
这两个例子之间存在很大差异。
order_cat(Pid, Name, Color, Description)
在一个请求的持续时间内使用监视器,并在收到成功响应后调用erlang:demonitor/2
。
subscribe(Pid)
更长久地建立了一个监视器。目的是事件客户端将在其主{'DOWN', Ref, process, Pid, Reason}
块中接收receive
消息并处理事件服务器死亡的事实。请注意subscribe(Pid)
如何将监视器引用返回为{ok, Ref}
,以供客户端用于此目的。不幸的是,这本书没有显示事件客户端的样子。
现在关于监视器与超时的更普遍的问题:监视的缺点是额外的成本很少,而且复杂性很小。与超时相比的优势包括:
Reason
部分会告诉您有关原因的信息。在某些应用程序中,客户端可能会根据原因尝试不同的恢复操作。gen_server:call/3
documentation也简要解释了这个问题。gen_server的实现:call / 2使用监视器。由于这是发送生成的erlang请求的数量,因此您可以相信它已经过优化并且是推荐的默认值。事实上,你应该使用OTP而不是自己动手。
请在此处查看source code。这是相关功能:
do_call(Process, Label, Request, Timeout) -> try erlang:monitor(process, Process) of Mref -> %% If the monitor/2 call failed to set up a connection to a %% remote node, we don't want the '!' operator to attempt %% to set up the connection again. (If the monitor/2 call %% failed due to an expired timeout, '!' too would probably %% have to wait for the timeout to expire.) Therefore, %% use erlang:send/3 with the 'noconnect' option so that it %% will fail immediately if there is no connection to the %% remote node. catch erlang:send(Process, {Label, {self(), Mref}, Request}, [noconnect]), receive {Mref, Reply} -> erlang:demonitor(Mref, [flush]), {ok, Reply}; {'DOWN', Mref, _, _, noconnection} -> Node = get_node(Process), exit({nodedown, Node}); {'DOWN', Mref, _, _, Reason} -> exit(Reason) after Timeout -> erlang:demonitor(Mref, [flush]), exit(timeout) end catch error:_ -> %% Node (C/Java?) is not supporting the monitor. %% The other possible case -- this node is not distributed %% -- should have been handled earlier. %% Do the best possible with monitor_node/2. %% This code may hang indefinitely if the Process %% does not exist. It is only used for featureweak remote nodes. Node = get_node(Process), monitor_node(Node, true), receive {nodedown, Node} -> monitor_node(Node, false), exit({nodedown, Node}) after 0 -> Tag = make_ref(), Process ! {Label, {self(), Tag}, Request}, wait_resp(Node, Tag, Timeout) end end.
答案 1 :(得分:2)
为什么这本书有时只使用超时,有时同时使用监视器和超时?
该过程可能会在超时到期之前终止,但您不希望无缘无故地等待更长时间。您希望呼叫最多 五秒,而不是总是五秒钟。
在下面是什么需要监视器,因为超时将有效地检测进程是否已关闭?
不会;终止不会触发超时,时间确实如此。