在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ 區(qū)塊鏈/ 分布式編程
注冊進程名稱
錯誤處理
完整示例
分布式編程
消息傳遞
if 與 case
健壯性
映射 (Map)
高階函數(shù) (Fun)
輸出至終端
更多關于列表的內(nèi)容
內(nèi)置函數(shù) (BIF)
模塊與函數(shù)
將大程序分在多個文件中
匹配、Guards 與變量的作用域
超時
列表
完整示例
頭文件
標準模塊與使用手冊
進程
記錄
增加健壯性后的完整示例
Erlang Shell
原子類型

分布式編程

下面我們進一步對 ping pong 示例程序進行改進。 這一次,我們要讓 “ping”、“pong” 進程分別位于不同的計算機上。要想讓這個程序工作,你首先的搭建一下分布式的系統(tǒng)環(huán)境。分布式 Erlang 系統(tǒng)的實現(xiàn)提供了基本的安全機制,它阻止未授權的外部設備訪問本機的 Erlang 系統(tǒng)。同一個系統(tǒng)中的 Erlang 要想相互通信需要設置相同的 magic cookie。設置 magic cookie 最便捷地實現(xiàn)方式就是在你打算運行分布式 Erlang 系統(tǒng)的所有計算機的 home 目錄下創(chuàng)建一個 .erlang.cookie 文件:

  • 在 windows 系統(tǒng)中,home 目錄為環(huán)境變量 $HOME 指定的目錄--這個變量的值可能需要你手動設置
  • 在 Linux 或者 UNIX 系統(tǒng)中簡單很多,你只需要在執(zhí)行 cd 命令后所進入的目錄下創(chuàng)建一個 .erlang.cookie 文件就可以了。

.erlang.cookie 文件只有一行內(nèi)容,這一行包含一個原子值。例如,在 Linux 或 UNIX 系統(tǒng)的 shell 執(zhí)行如下命令:

$ cd
$ cat > .erlang.cookie
this_is_very_secret
$ chmod 400 .erlang.cookie

使用 chmod 命令讓 .erlang.cookie 文件只有文件擁者可以訪問。這個是必須設置的。

當你想要啟動 erlang 系統(tǒng)與其它 erlang 系統(tǒng)通信時,你需要給 erlang 系統(tǒng)一個名稱,例如:

$erl -sname my_name

在后面你還會看到更加詳細的內(nèi)容。如果你想嘗試一下分布式 Erlang 系統(tǒng),而又只有一臺計算機,你可以在同一臺計算機上分別啟動兩個 Erlang 系統(tǒng),并分別賦予不同的名稱即可。運行在每個計算機上的 Erlang 被稱為一個 Erang 結點(Erlang Node)。

(注意:erl -sname 要求所有的結點在同一個 IP 域內(nèi)。如果我們的 Erlang 結點位于不同的 IP 域中,則我們需要使用 -name,而且需要指定所有的 IP 地址。)

下面這個修改后的 ping pong 示例程序可以分別運行在兩個結點之上:

-module(tut17).

-export([start_ping/1, start_pong/0,  ping/2, pong/0]).

ping(0, Pong_Node) ->
    {pong, Pong_Node} ! finished,
    io:format("ping finished~n", []);

ping(N, Pong_Node) ->
    {pong, Pong_Node} ! {ping, self()},
    receive
        pong ->
            io:format("Ping received pong~n", [])
    end,
    ping(N - 1, Pong_Node).

pong() ->
    receive
        finished ->
            io:format("Pong finished~n", []);
        {ping, Ping_PID} ->
            io:format("Pong received ping~n", []),
            Ping_PID ! pong,
            pong()
    end.

start_pong() ->
    register(pong, spawn(tut17, pong, [])).

start_ping(Pong_Node) ->
    spawn(tut17, ping, [3, Pong_Node]).

我們假設這兩臺計算分別稱之為 gollum 與 kosken。在 kosken 上啟動結點 ping。在 gollum 上啟動結點 pong。

在 kosken 系統(tǒng)上(Linux/Unix 系統(tǒng)):

kosken> erl -sname ping
Erlang (BEAM) emulator version 5.2.3.7 [hipe] [threads:0]

Eshell V5.2.3.7  (abort with ^G)
(ping@kosken)1>

在 gollum 上:

gollum> erl -sname pong
Erlang (BEAM) emulator version 5.2.3.7 [hipe] [threads:0]

Eshell V5.2.3.7  (abort with ^G)
(pong@gollum)1>

下面,在 gollum 上啟動 "pong" 進程:

(pong@gollum)1> tut17:start_pong().
true

然后在 kosken 上啟動 “ping” 進程(從上面的代碼中可以看出,start_ping 的函數(shù)的其中一個參數(shù)為 “pong” 進程所在結點的名稱):

(ping@kosken)1> tut17:start_ping(pong@gollum).
<0.37.0>
Ping received pong
Ping received pong 
Ping received pong
ping finished

如上所示,ping pong 程序已經(jīng)開始運行了。在 “pong” 的這一端:

(pong@gollum)2>
Pong received ping                 
Pong received ping                 
Pong received ping                 
Pong finished                      
(pong@gollum)2>

再看一下 tut17 的代碼,你可以看到 pong 函數(shù)根本就沒有發(fā)生任何改變,無論 “ping” 進程運行在哪個結點下,下面這一行代碼都可以正確的工作:

{ping, Ping_PID} ->
    io:format("Pong received ping~n", []),
    Ping_PID ! pong,

因此,Erlang 的進程標識符中包含了程序運行在哪個結點上的位置信息。所以,如果你知道了進程的進程標識符,無論進程是運行在本地結點上還是其它結點上面,"!" 操作符都可以將消息發(fā)送到該進程。

要想通過進程注冊的名稱向其它結點上的進程發(fā)送消息,這時候就有一些不同之處了:

{pong, Pong_Node} ! {ping, self()},

這個時候,我們就不能再只用 registered_name 作為參數(shù)了,而需要使用元組 {registered_name,node_name} 作為注冊進程的名稱參數(shù)。

在之前的代碼中了,“ping”、“pong” 進程是在兩個獨立的 Erlang 結點上通過 shell 啟動的。 spawn 也可以在其它結點(非本地結點)啟動新的進程。

下面這段示例代碼也是一個 ping pong 程序,但是這一次 “ping” 是在異地結點上啟動的:

-module(tut18).

-export([start/1,  ping/2, pong/0]).

ping(0, Pong_Node) ->
    {pong, Pong_Node} ! finished,
    io:format("ping finished~n", []);

ping(N, Pong_Node) ->
    {pong, Pong_Node} ! {ping, self()},
    receive
        pong ->
            io:format("Ping received pong~n", [])
    end,
    ping(N - 1, Pong_Node).

pong() ->
    receive
        finished ->
            io:format("Pong finished~n", []);
        {ping, Ping_PID} ->
            io:format("Pong received ping~n", []),
            Ping_PID ! pong,
            pong()
    end.

start(Ping_Node) ->
    register(pong, spawn(tut18, pong, [])),
    spawn(Ping_Node, tut18, ping, [3, node()]).

假設在 Erlang 系統(tǒng) ping 結點(注意不是進程 “ping”)已經(jīng)在 kosken 中啟動(譯注:可以理解 Erlang 結點已經(jīng)啟動),則在 gollum 會有如下的輸出:

<3934.39.0>
Pong received ping
Ping received pong
Pong received ping
Ping received pong
Pong received ping
Ping received pong
Pong finished
ping finished

注意所有的內(nèi)容都輸出到了 gollum 結點上。這是因為 I/O 系統(tǒng)發(fā)現(xiàn)進程是由其它結點啟動的時候,會自將輸出內(nèi)容輸出到啟動進程所在的結點。

上一篇:錯誤處理下一篇:列表