我正在阅读LearnYouSomeErlang并找到以下代码:
我的问题是,为什么我们需要Ref的event功能.我认为给出的理由Ref就像request-id一样.
如果我发送多个请求dont_give_crap,当我收到回复时,Ref作为回应告诉我它是哪个ID.
但是,由于event是阻止而我只发送一个请求,在哪种情况下,我能够从同一个进程发送多个请求dont_give_crap process吗?目的是Ref什么?
-module(cat_fsm).
-export([start/0, event/2]).
start() ->
spawn(fun() -> dont_give_crap() end).
event(Pid, Event) ->
Ref = make_ref(), % won't care for monitors here
Pid ! {self(), Ref, Event},
receive
{Ref, Msg} -> {ok, Msg}
after 5000 ->
{error, timeout}
end.
dont_give_crap() ->
receive
{Pid, Ref, _Msg} -> Pid ! {Ref, meh};
_ -> ok
end,
io:format("Switching to 'dont_give_crap' state~n"),
dont_give_crap().
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么我们需要Ref
这就像验证码.如果有进程的Pid,任何其他进程都可以向您的进程发送消息.
我认为给出的理由是Ref就像request-id.
Ref更像是回复ID.这是进程期望在回复中收到的id.如果你写:
receive
Msg -> %%do something
end
Run Code Online (Sandbox Code Playgroud)
然后发送到您的进程邮箱的任何邮件都将匹配该模式,您将不知道它来自何处.如果你写:
receive
{Pid, Msg} -> %%do something
end
Run Code Online (Sandbox Code Playgroud)
您仍然无法确定该消息来自进程Pid.您的另一个进程可能有多个Pid它正在回复并意外地使用了错误的Pid来处理该消息.
但是,如果你发送一个参与你的处理Pid的请求,那么进程Pid可以回复一条消息,其中包含收到的Ref和它的Pid,然后你可以从你的邮箱中提取包含Ref和发件人Pid的消息并确保它来自进程Pid(实际上,进程Pid可以将Ref发送到其他进程,所以你仍然无法绝对确定).
如果你有一个带有1,000个进程的erlang应用程序相互发送100条消息,那么如果你只验证了Pid回复的来源,那么它可能更容易出错.
编辑:我刚刚阅读有关gen_udp和套接字的信息,事实证明有些服务器可以复制回复.假设发生这种情况,客户端从邮箱中提取第一个回复,如下所示:
receive
{Pid, Msg1} -> Msg1
end
Run Code Online (Sandbox Code Playgroud)
然后客户端发送第二个请求并等待回复:
receive
{Pid, Msg2} -> Msg2
end
Run Code Online (Sandbox Code Playgroud)
那么,该模式将提取对第一个请求的重复回复 - 而不是对第二个请求的回复.但是如果一个唯一的Ref并且同时发送了第一个和第二个请求:
Pid = ...,
Ref1 = ...,
Pid ! {self(), Ref1, Msg1},
receive
{Pid, Ref1, Reply1} -> Reply1
end,
Ref2 = ...,
Pid ! {self(), Ref2, Msg2},
receive
{Pid, Ref2, Reply2} -> Reply2
end.
Run Code Online (Sandbox Code Playgroud)
然后第二次接收与第一次请求的重复回复不匹配.这是一个很好地使用Ref的具体例子.
| 归档时间: |
|
| 查看次数: |
81 次 |
| 最近记录: |