2017-08-09 76 views
3

如果我使用register(atom, spawn..)註冊新衍生過程,或者如果我註冊Pid = spawn..,它有什麼區別嗎?Erlang:註冊過程和將Pid分配給變量的區別

讓我們先建立一個簡單的服務器循環:

-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, []). 

舉個例子,我剛剛從編程二郎書的舊程序這樣做

編譯後,我做

​​

然後,我打電話給他們,並得到結果如下:

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 

爲什麼客戶端無法從服務器當我使用註冊原子得到了什麼?服務器顯然從客戶端收到消息。

我可以證實,服務器發送一個消息,因爲在上面的,如果我做

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> 

所以我的結論是郵箱已經從先前的命令服務器的消息,這是爲什麼在收到並打印服務器消息之前打印客戶端輸出...

我在想什麼?爲什麼在使用註冊原子時收到消息時會出現問題?

回答

4

receive在你的client/2功能等待消息匹配{Pid_server, Geom_tuple, Area}。當您通過q作爲參數時,Pid_serverq,但服務器向客戶端發送返回的消息是一個元組,其第一個元素始終是服務器的實際PID,而不是其名稱,這意味着您的receive最終結束在after區塊中。

有很多方法可以解決這個問題。如果Pid_server是原子,您可以修改client/2以使用whereis/1獲取已註冊過程的PID並將其用於receive中。

最好的方法是在這裏使用引用(請參閱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.