让我们仔细看看这一点。 “rpc”是什么意思? “远程过程调用” - 当然。但是在Erlang的一切是一个rpc,所以我们倾向于不使用这个术语。相反,我们区分同步消息(呼叫者阻止,等待响应)和异步消息(呼叫者只需触发消息并在世界中无需关心的情况下运行)。我们倾向于使用术语“呼叫”来表示同步消息,而使用“施放”表示异步消息。
我们可以很容易地编写,因为调用看起来很像上面的rpc,在Erlang中增加了一个独特的参考值来标记消息并监视我们发送消息的过程,以防万一它崩溃(所以我们没有得到左边挂,等待永远不会到来的回应......我们将在一点触摸你的代码):
% Synchronous handler
call(Proc, Request) ->
Ref = monitor(process, Proc),
Proc ! {self(), Ref, Request},
receive
{Ref, Res} ->
demonitor(Ref, [flush]),
Res;
{'DOWN', Ref, process, Proc, Reason} ->
{fail, Reason}
after 1000 ->
demonitor(Ref, [flush]),
{fail, timeout}
end.
Cast是更容易一点:
cast(Proc, Message) ->
Proc ! Message,
ok.
以上调用的定义意味着我们发送给的进程将接收一条形式为{SenderPID, Reference, Message}
的消息。请注意,这是不同比{sender, reference, message}
,因为小写字母值为atoms,这意味着它们是它们自己的值。
当我们receive
消息我们是匹配关于接收到的消息的形状和值。这意味着,如果我有
receive
{number, X} ->
do_stuff(X)
end
在我的代码
,它不会匹配过程坐在那receive
得到一个消息{blah, 25}
。如果它收到另一个消息{number, 26}
那么它将匹配,即receive
将调用do_stuff/1
并且该过程将继续。 (这两件事 - atoms
和Variables
之间的区别与receive
作品中的匹配方式 - 是您的代码挂起的原因。)初始邮件{blah, 25}
仍将位于邮箱中,但位于队列的前端,所以下一个receive
有机会匹配它。邮箱的这个属性有时非常有用。
但是,什么是一个全部看起来像?
高于你期望三种消息:
{insert, Key, Value}
{retrieve, Key}
stop
你穿起来有所不同,但是这是你想什么营业结束去做。通过我在上面写到的call/2
函数运行插入消息将会看起来像这样:{From, Ref, {insert, Key, Value}}
。所以,如果我们期望从进程的接收循环中得到任何响应,我们需要按照确切的形式进行匹配。我们如何捕捉意外消息或形成不良的消息?在receive
条款的最后,我们可以把一个赤裸裸的变量,以匹配任何其他:
loop(State) ->
receive
{From, Ref, {insert, Key, Value}} ->
NewState = insert(Key, Value, State),
From ! {Ref, ok},
loop(NewState);
{From, Ref, {retrieve, Key}} ->
Value = retrieve(Key, State),
From ! {Ref, {ok, Value}},
loop(State);
{From, Ref, stop} ->
ok = io:format("~tp: ~tp told me to stop!~n", [self(), From]),
From ! {Ref, shutting_down},
exit(normal)
Unexpected ->
ok = io:format("~tp: Received unexpected message: ~tp~n",
[self(), Unexpected]),
loop(State)
end.
你会发现,我不使用进程字典。不要使用过程字典。这不是它的目的。你会覆盖重要的东西。或者丢掉重要的东西。或者......呃,不要这样做。使用字典或映射或gb_tree或其他代替,并将其作为过程'State
变量传递。一旦你稍后开始编写OTP代码,这对你来说将变得非常自然。
玩弄这些东西,你很快就会高兴地发送垃圾邮件到你的程序死亡。
第一个问题,在你走之前:Erlang *没有类或方法*。一切都是功能。每个函数都会返回一个值。虽然有[*进程*,而不是*类*](http://stackoverflow.com/questions/32294367/erlang-process-vs-java-thread/32296577#32296577),你可以发送*消息* ,但他们如何回应这些问题的方式与方法完全不同。 – zxq9
谢谢。你是对的。我仍然不明白Erlang的一切工作原理 –