Inn*_*ynn 4 concurrency erlang
这段代码是由我们的老师给我们的,但很遗憾,没有解释.我们刚刚在课堂上试过这个,然后被解雇了.
如果有人能够彻底向我解释这段代码,那将会非常有帮助.提前致谢.
-module(pingpong).
-compile(export_all).
start_pong() ->
register(pong, spawn(pingpong,pong,[])).
pong() ->
receive
finished ->
io:format("Pong finished ~n");
{ping, Ping_Pid} ->
io:format("i am the receiver ~n"),
Ping_Pid ! pong,
pong()
end.
start_ping(Pong_Node) ->
spawn(pingpong, ping, [3, Pong_Node]).
ping(0, Pong_Node) ->
{pong, Pong_Node} ! finished,
io:format("Pong finished ~n");
ping(N, Pong_Node) ->
{pong, Pong_Node} ! {ping, self()},
receive
pong ->
io:format("i am the sender ~n")
end,
ping(N-1,Pong_Node).
Run Code Online (Sandbox Code Playgroud)
我们来看看前两行.
-module(pingpong).
-compile(export_all).
Run Code Online (Sandbox Code Playgroud)
第一个是模块声明,其参数是一个原子(换句话说,是一个小写的单词,没有引号).取自学习你一些Erlang:
-module(Name).
这始终是文件的第一个属性(和语句),并且有充分的理由:它是当前模块的名称,其中Name是一个原子.这是您用来从其他模块调用函数的名称.调用是使用M:F(A)表单进行的,其中M包括模块名称,F函数和A参数.
第二句告诉编译器将所有声明的函数公开,即,F您在该模块上编写的每个函数都可以被外人调用为pingpong:F.
这可能会简化您第一次学习时的过程,但这通常是一种不好的做法.请参阅此问题.
我们现在来看看这些功能.
start_pong() ->
register(pong, spawn(pingpong,pong,[])).
Run Code Online (Sandbox Code Playgroud)
这可能是您的代码开始的地方.编译模块,然后调用pingpong:start_pong().给定计算机或节点的Erlang shell.所有这个功能都是"将名称pong注册为我即将创建的进程的标识符,spawn".
因此,spawn创建一个Erlang进程.spawn也是一个内置函数(BIF),因此不需要您添加其模块名称.它的论点是spawn(Module, Exported_Function, List of Arguments),如文档中所示.
回顾一下start_pong,它所做的只是"创建一个进程,该进程将通过运行pong此模块中的函数开始,没有参数,并调用该进程pong ".
pong() ->
receive
finished ->
io:format("Pong finished ~n");
{ping, Ping_Pid} ->
io:format("i am the receiver ~n"),
Ping_Pid ! pong,
pong()
end.
Run Code Online (Sandbox Code Playgroud)
新创建的进程start_pong将运行此功能.Erlang中的每个进程都有自己的邮箱.进程通过在这些邮箱中保留邮件来相互通信.消息几乎可以是任何内容.将它们视为您希望在进程之间发送的一些数据.
新进程进入receive语句,告诉它从其邮箱中获取邮件,或者等到有一些邮件.然后,当收到消息时,它使用模式匹配来查找适当的操作.如果您习惯于命令式语言,请将其视为一个switch,否则请忽略此语句.
如果进程有一个带有单个原子的消息finished,它将Pong finished在控制台中打印并退出.
如果进程有一个与atom ping和一个进程标识符(pid - 每个进程都有一个)的消息,那么它将执行该函数的剩余代码.
大写字母Ping_Pid告诉Erlang将消息所具有的任何第二个值分配给具有名称的变量Ping_Pid.只是碰巧你期待一个pid.
在进入这种情况时,它所做的是打印i am the receiver,然后将带有原子的消息发送pong到由所识别的过程Ping_Pid- 这就是!操作员的用途.Finnaly,函数调用自己,以便再次查看邮箱.
您将在控制台上编写的下一件事,可能是在另一个节点/机器上,将调用start_ping.
start_ping(Pong_Node) ->
spawn(pingpong, ping, [3, Pong_Node]).
Run Code Online (Sandbox Code Playgroud)
正如我们之前看到的,所有这一切都是创建一个运行ping函数的进程,带有参数3并且Pong_Node它接收,这是运行第一个进程的机器(节点).
ping(0, Pong_Node) ->
{pong, Pong_Node} ! finished,
io:format("Pong finished ~n");
ping(N, Pong_Node) ->
{pong, Pong_Node} ! {ping, self()},
receive
pong ->
io:format("i am the sender ~n")
end,
ping(N-1,Pong_Node).
Run Code Online (Sandbox Code Playgroud)
这个函数在两种情况下定义(注意第一个ping块结束;,而不是.- 这告诉Erlang有更多的定义函数).
你用它3作为第一个参数来调用它.由于3不匹配0,进程执行第二种情况,N作为其参数.
此过程将该对发送{ping, self()}到给定的进程,该进程{pong, Pong_Node}遵循语法{registered_name, node_name}.self()用于检索当前进程自己的pid.
在此之后,该过程等待pong响应,并再次重复此过程,同时N大于零.
当N达到零时,执行第一种情况,发送finished到{pong, Pong_Node}结束执行.
如果您觉得这个解释不完整,您可能还会看一下教程,它描述了这个确切的程序.