这段代码是由我们的老师给我们的,但很遗憾,没有解释。我们刚刚在课堂上试过这个,然后被解雇了。
如果有人能够彻底向我解释这段代码,那将会非常有帮助。提前谢谢。-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).
答案 0 :(得分:8)
让我们来看看前两行。
-module(pingpong).
-compile(export_all).
第一个是模块声明,其参数是 atom (换句话说,是一个小写的单词,没有引号)。取自了解你一些Erlang :
<强>
-module(Name).
强>
这始终是文件的第一个属性(和语句),并且有充分的理由:它是当前模块的名称,其中Name是一个原子。这是您用来从其他模块调用函数的名称。调用是使用M:F(A)
表单进行的,其中M
是模块名称,F
函数和A
参数。
第二句告诉你的编译器使所有声明的函数 public ,即,你在该模块上编写的每个函数F
都能被调用由外人pingpong:F
这可能会简化您第一次学习时的过程,但这通常是一种不好的做法。请参阅this question。
现在让我们来看看这些功能。
start_pong() ->
register(pong, spawn(pingpong,pong,[])).
这可能是您的代码开始的地方。编译模块,然后在给定计算机或节点的Erlang shell中调用pingpong:start_pong().
。所有这个功能都是“将名称 pong 注册为我即将创建的进程的标识符,spawn
”。
因此,spawn
创建了一个Erlang进程。 spawn
也是内置函数(BIF),因此不需要在其前面添加模块名称。它的论点是spawn(Module, Exported_Function, List of Arguments)
,见in the documentation
回顾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.
start_pong
中新创建的流程将运行此功能。 Erlang中的每个进程都有自己的邮箱。进程通过在这些邮箱中保留邮件来相互通信。消息可能几乎任何内容。将它们视为您希望在进程之间发送的一些数据。
新进程进入receive
语句,该语句告诉它从其邮箱中获取邮件,或者等到有一些邮件。然后,当收到消息时,它使用模式匹配来查找相应的操作。如果您习惯于命令式语言,请将其视为switch
,否则请忽略此语句。
如果进程有一条带有单个原子finished
的消息,它会在控制台中输出Pong finished
并退出。
如果进程的消息是与原子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]).
正如我们之前看到的,所有这一切都是创建一个运行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).
此函数在两种情况下定义(请注意,第一个ping
块以;
结束,而不是.
- 这告诉Erlang还有更多定义函数的内容。 / p>
您可以使用3
作为第一个参数调用它。由于3
与0
不匹配,因此该过程执行第二种情况,其中N
为其参数。
此过程将{ping, self()}
对发送到{pong, Pong_Node}
给出的进程,该进程遵循语法{registered_name, node_name}
。 self()
用于检索当前进程自己的 pid
在此之后,该过程等待pong
响应,并再次重复此过程,而N
大于零。
当N
达到零时,执行第一种情况,将finished
发送到{pong, Pong_Node}
,然后结束执行。
如果你觉得这个解释不完整,你也可以看看at the tutorial,它描绘了这个确切的程序。