Erlang服务器代码的分析与学习(一)

The Echo process

%%------------------------------------------------------------

-module(echo).
-compile(export_all).

go() ->
register(echo, spawn(echo, loop, [])),
echo ! {self(), hello},
Pid = whereis(echo),
receive
{Pid, Msg} -> 
io:format("~w~n", [Msg])
end,
echo ! stop.


loop() ->
receive
{From, Msg} ->
From ! {self(), Msg},
loop();
stop ->
true
end.

 %%------------------------------------------------------------

代码易错点:

(1)io:format/2函数的第二个参数是个list,务必记得写成[]的形式。

(2)receive expression内部匹配模式以分号分隔,内部以逗号分隔,end之前的模式结尾处不加分号。


流程:

(1)母进程执行go()。

(2)spawn函数创建一个子进程来执行echo模块中的loop函数,函数参数列表是[],将创建的子进程的Pid作为参数传入register函数的第二个参数,将这个子进程起个别名叫做echo。

(子线程被创建完成后,就开始执行Echo:loop())

(3)子线程执行loop(),进入receive状态,等待接收消息,此时mailbox为空,所以子线程suspend。

(4)母线程继续执行,向ID为Pid的线程(即子线程)发送消息,内容是个tuple,第一个元素是self()。返回的是母线程自己的Pid,第二个元素是个atom,hello。

(这里whereis(Alias)的用处是返回别名Alias对应的线程的Pid,因为erlang编译器的原因,receive expression的匹配模式内{Whereis(echo), Msg}这样的嵌套格式会返回"illegal pattern"的错误,更不能将此处的Pid用Alias代替,因为Alias是个atom,匹配模式内此处应当是个Pid,是<0.101.0>这样的格式。)

(5)接着,母线程在receive语句下进入suspend状态,等待接收消息。

(6)子线程接收到母线程发来的消息{self(), hello},成功匹配了{From, Msg},这里From与self()即母线程Pid匹配,Msg与atom类型的变量hello匹配。

(7)匹配成功后,子线程用接收到的母线程的Pid(即匹配后的From)向母线程发送消息,消息内容也是个tuple,第一个元素是self(),返回的是子线程自己的Pid,第二个元素是Msg(即匹配后,母线程之前发来的内容,hello)。

(8)发送完成后,子线程通过自我调用loop(),重新执行receive语句进入suspend状态等待消息。

(9)刚刚母线程在receive语句下进入suspend状态,现在收到了子线程发来的反馈消息,于是将收到的消息与{Pid, Msg}进行模式匹配,Pid为之前母线程中创建子线程的Pid,与子线程消息中传来的self()匹配成功,Msg与发来的hello匹配(绑定)。并作为参数传入下面调用的io:format/2函数,在shell里面将它打印出来。

(10)打印完成后,母线程向子线程发送stop,子线程收到stop,与第二行的stop模式匹配成功,返回true,通过一层层向上返回,最后end。子线程中的loop()函数执行结束。


%% -------------------------------------------------------------------------------------------------------------------------------------------------


必备函数介绍:

spawn(Module, Function, Arguments)

为了运行并发性的代码,我们需要创建更多的线程,我们使用spawn(Module, Function, Arguments)这个BIF(built-in function)来建一个新的线程,它会执行从模块Module中exported出来的函数Function,Function的参数列表是Arguments。这个spawn/3函数会返回新建线程的Pid(Process Identifier)。


register(Alias, Pid)

一般我们用别名来注册那些提供特定服务的线程,这些别名可以被当成那些线程的Pid使用。注册一个线程的BIF是register(Alias, Pid),这里的Alias是个atom,Pid是被注册的线程的ID。


Pid ! Message

这表示将Message(可以是List,Tuple等等)发送到进程标识为Pid的进程的消息队列中。即当前进程向Pid的进程发送Message。


receive / end

进程使用receive关键字,从process mailbox中获取消息。receive语句是一个由分隔的receive和end关键字组成的结构,中间可以包含多个语句。一旦执行receive语句,process mailbox里面第一条消息(最旧的)会轮流与receive表达式里面的每一个pattern进行匹配。

receive关键词被用来让进程等待从其他进程发来的消息。

 • If a successful match  occurs,the message is retrieved from the mailbox, the variables in the pattern arebound to the matching parts of the message, and the body of the clause isexecuted.

• If none of the clauses matches , thesubsequent messages in the mailbox are patternmatched one by one against all ofthe clauses until either a message matches a clause or all of the messages havefailed all of the possible pattern matches.


%% -------------------------------------------------------------------------------------------------------------------------------------------------


以下部分来源于网页内容(原文网址:http://www.erlang-cn.com/121.htmlerlang 2013年11月03日 于 Erlang教程 发表

“Erlang 进程之间的消息可以是任何简单的 Erlang 项。比如说,可以是列表、元组、整数、原子、进程标识等等。 

每个进程都有独立的消息接收队列。新接收的消息被放置在接收队列的尾部。当进程执行receive 时,消息中第一个消息与与 receive 后的第一个模块进行匹配。如果匹配成功,则将该消息从消息队列中删除,并执行该模式后面的代码。 

然而,如果第一个模式匹配失败,则测试第二个匹配。如果第二个匹配成功,则将该消息从消息队列中删除,并执行第二个匹配后的代码。如果第二个匹配也失败,则匹配第三个,依次类推,直到所有模式都匹配结束。如果所有匹配都失败,则将第一个消息留在消息队列中,使用第二个消息重复前面的过程。第二个消息匹配成功时,则执行匹配成功后的程序并将消息从消息队列中取出(将第一个消息与其余的消息继续留在消息队列中)。如果第二个消息也匹配失败,则尝试第三个消息,依次类推,直到尝试完消息队列所有的消息为止。如果所有消息都处理结束(匹配失败或者匹配成功被移除),则进程阻塞,等待新的消息的到来。上面的过程将会一直重复下去。 

Erlang 实现是非常 “聪明” 的,它会尽量减少 receive 的每个消息与模式匹配测试的次数。”

 




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值