最初の 2 行を見てみましょう。
-module(pingpong).
-compile(export_all).
1 つ目はモジュール宣言で、その引数はアトム(つまり、引用符なしの小文字の単語) です。Learn You Some Erlangから取得:
-module(Name).
これは常にファイルの最初の属性 (およびステートメント) であり、それには正当な理由があります: これは現在のモジュールの名前であり、Name はアトムです。これは、他のモジュールから関数を呼び出すために使用する名前です。呼び出しは、モジュール名、関数、および引数のM:F(A)形式で行われます。MFA
2 番目の文は、宣言されたすべての関数をpublicにするようコンパイラに指示します。つまり、そのモジュールに記述したすべての関数Fは、部外者が として呼び出すことができますpingpong:F。
これにより、最初に学習するときのプロセスが簡素化される場合がありますが、通常は悪い習慣です。この質問を参照してください。
さっそく機能を見ていきましょう。
start_pong() ->
register(pong, spawn(pingpong,pong,[])).
おそらく、ここからコードが開始されます。pingpong:start_pong().モジュールをコンパイルしてから、特定のマシンまたはノードの Erlang シェルを呼び出します。この関数が行うのは、 「作成しようとしているプロセスの識別子としてpongという名前を登録する」spawnことだけです。
そこで、spawnErlang プロセスを作成します。spawnも組み込み関数 (BIF) であるため、そのモジュール名を先頭に追加する必要はありません。ドキュメントspawn(Module, Exported_Function, List of Arguments)に見られるように、その引数は、です。
を振り返ってみると、 「このモジュール内の関数を引数なしで実行して開始するプロセスを作成し、そのプロセスをpongと呼ぶ」だけです。
start_pongpong
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てください。それ以外の場合は、このステートメントを無視してください。
プロセスに単一の atom を含むメッセージがある場合、コンソールfinishedに出力されて終了します。アトムとプロセス識別子( pid - すべてのプロセスに 1 つある)
のペアであるメッセージがプロセスにある場合、プロセスは関数の残りのコードを実行します。Pong finished
ping
大文字Ping_Pidは、Erlang に、メッセージが持っている 2 番目の値を という名前の変数に代入するように指示しますPing_Pid。たまたまpidが必要です。
このケースに入ったときに行うことは、 printi am the receiverであり、アトムを含むメッセージをpongによって識別されるプロセスに送信します。Ping_Pidこれが!オペレーターの目的です。最後に、関数は自分自身を呼び出して、メールボックスをもう一度調べます。
コンソール (おそらく別のノード/マシン) に次に書き込むのは、 への呼び出し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).
この関数は 2 つのケースで定義されます (最初のブロックは -ではなく でping終わることに注意してください。これは、関数を定義する必要があることを Erlang に伝えます)。;.
3最初の引数として呼び出します。3は と一致しないため0、プロセスはN引数として で 2 番目のケースを実行します。
このプロセスは、構文 に従う で{ping, self()}指定されたプロセスにペアを送信します。現在のプロセス自身のpidを取得するために使用されます。
この後、プロセスは応答を待ち、これを繰り返します。while は 0 より大きくなります。{pong, Pong_Node}{registered_name, node_name}self()
pongN
ゼロにN達すると、最初のケースが実行され、 に送信され、finished実行が{pong, Pong_Node}終了します。
この説明が不完全であると思われる場合は、この正確なプログラムを示しているチュートリアルも参照してください。