Erlang:注册过程和将Pid分配给变量之间的区别

时间:2017-08-09 07:07:55

标签: erlang

如果我使用register(atom, spawn..)Pid = spawn..注册新生成的流程,会有所不同吗?

举一个例子,我只是用编程Erlang书中的一个旧程序来做到这一点:

让我们首先制作一个简单的服务器循环:

-module(geometry_server).
-export([loop/0]).

loop() ->
    receive
        {Client, {square, S} = Tuple} ->
            io:format("Server: Area of square of Side ~p is ~p and Client was ~p~n", [S, S*S, Client]),
            Client ! {self(), Tuple,  S*S},
            loop()
    end.

现在是客户:

-module(geometry_client).
-export([client/2, start_server/0]).

client(Pid_server, Geom_tuple) ->
    Pid_server ! {self(), Geom_tuple},
    receive
        {Pid_server, Geom_tuple, Area} -> io:format("Client: Area of ~p is ~p and       server was ~p~n", [Geom_tuple, Area, Pid_server])

    after 1000 ->
          io:format("~p~n",["received nothing from server"] )
    end.

start_server() ->    spawn(geometry_server, loop, []).

编译后,我做

 register(q, Q = geometry_client:start_server()).

然后我打电话给他们,得到如下结果:

5> geometry_client:client(Q, {square,2}).
Server: Area of square of Side 2 is 4 and Client was <0.60.0>
Client: Area of {square,2} is 4 and server was <0.77.0>
ok
6> geometry_client:client(q, {square,2}).
Server: Area of square of Side 2 is 4 and Client was <0.60.0>
"received nothing from server"
ok

为什么客户端在使用注册的atom时没有收到服务器上的任何内容?服务器显然收到了来自客户端的消息。

我可以确认服务器发送了一条消息,因为上面的话后我做了

7> geometry_client:client(whereis(q), {square,2}).
Client: Area of {square,2} is 4 and server was <0.77.0>
Server: Area of square of Side 2 is 4 and Client was <0.60.0>
ok
12>

所以我得出结论,邮箱已经有来自上一个命令的来自服务器的消息,这就是在收到并打印服务器消息之前打印客户端输出的原因......

我错过了什么?当我使用已注册的原子时,为什么接收消息时出现问题?

1 个答案:

答案 0 :(得分:3)

receive函数中的client/2等待与{Pid_server, Geom_tuple, Area}匹配的邮件。当您传递q作为参数时,Pid_serverq,但服务器将返回的消息发送到客户端是一个元组,第一个元素始终是服务器的实际PID,而不是其名称,这意味着您的receive最终会出现在after区块中。

有很多方法可以解决这个问题。您可以修改client/2以使用whereis/1获取已注册流程的PID,并在receive中使用{如果Pid_server是原子。

最好的方法是在这里使用引用(参见make_ref/0)。在向服务器发送消息时创建引用,服务器将其发送回响应中。这样,您就可以保证您已收到刚刚发送的请求的回复,因为make_ref/0返回的每个引用都保证是唯一的。

client/2中,执行:

client(Pid_server, Geom_tuple) ->
    Ref = make_ref(),
    Pid_server ! {Ref, self(), Geom_tuple},
    receive
        {Ref, Geom_tuple, Area} -> io:format("Client: Area of ~p is ~p and       server was ~p~n", [Geom_tuple, Area, Pid_server])
    after 1000 ->
          io:format("~p~n",["received nothing from server"] )
    end.

在服务器中:

loop() ->
    receive
        {Ref, Client, {square, S} = Tuple} ->
            io:format("Server: Area of square of Side ~p is ~p and Client was ~p~n", [S, S*S, Client]),
            Client ! {Ref, Tuple,  S*S},
            loop()
    end.