プロセス間通信
Erlangでは、異なるプロセス同士は何も共有せず、それぞれのプロセスは完全に分離しています。プロセス間の通信手段はメッセージだけです。前述のように、products_collectorプロセスは、(1) 各partial_compute関数から(それぞれの計算の完了時)、および(2)関数computeから(すべてのpartial_compute関数が終了し、結果のリストを要求しているとき)、メッセージを受け取ります。この2つの場合のメッセージ送信の構文は以下のとおりです。
ProductsCollector_PID ! {get_products,self()},
ProductsCollector_PID ! {add_product,multiplication(FactorsInTheInterval)}.
どちらの場合も、送信するメッセージは、メッセージの送信先プロセスのPID、演算子!、タプル形式のメッセージ本体で構成されます。たとえば、シナリオ1のメッセージ本体には、アトムget_productとメッセージの送信元プロセスのPIDが含まれます。送信元プロセスのPIDは、送信したメッセージに対して送信先プロセスから応答を受け取るときに必要になります。
送信されたメッセージはすべて非同期なので、プログラムは応答を待たず(応答が来る予定の場合)、即座にその次の命令を実行します。
次に、関数products_collectorで、プロセスがメッセージの到着を待機してアクションを実行する方法を見てみましょう。
products_collector(L, Loop_PID) ->
receive
{add_product, Product} ->
Loop_PID ! {done},
products_collector([Product|L], Loop_PID);
{get_products, Client_PID} ->
Client_PID ! {products, L},
products_collector(L, Loop_PID);
{done} ->
noop
end.
電子メールにたとえると、プロセスには受信箱があり、着信メッセージはすべてキューに入れられ、FIFO方式とパターンマッチングメカニズムを使って処理されます。
こうした仕組み全体を理解するには、receive ... end構造を理解することがとても重要です。着信メッセージのキューと、各種パターンを表すタプル一式があるとします。新しいメッセージが届いたとき、そしてそのときのみ、以下のことが発生します。
まず、キュー内の最初のメッセージ(最初に到着したメッセージ)が最初のパターンとマッチングされます。
- マッチした場合:その次の文が実行されます。そのメッセージはキューから削除されます
- マッチしなかった場合:そのメッセージが次のパターンとマッチングされます
最初のメッセージがリスト内のどのパターンとも一致しなかった場合は、
- そのメッセージは「退避キュー」というキューへ入れられ、2番目のメッセージの処理へ進みます
- 退避キュー内のメッセージは、新しいメッセージが着いた後も、もうマッチングされません
receive ... end構造の追加機能の1つとしてタイマーがあります。これは、新しいメッセージの待機を一定時間後に中止し、なんらかのアクションを実行してから、退避キュー内のメッセージをメールボックスに元の順番どおりに戻します。
Debian Linuxでコードを実行するには
1998年、Ericsson社はErlangをオープンソース製品として公開し、WebサイトErlang.orgを開設しました。このサイトでは、コードのほか、Linux、Mac、Windows環境用のErlangインタープリタのバイナリも提供されています。コードダウンロードには、各種モジュールライブラリや、Mnesia(PDF)というリアルタイム分散データベースもあります。このフレームワーク全体をErlang Open Telecom Platform(OTP)と呼びます。
Debian Linuxでは、以下のコマンドでインストールします。
apt-get install erlang
ツールやユーティリティ関数も含めたErlang OTPプラットフォーム一式がこれでインストールされます。
Erlangのコードをインタープリタ用擬似コードにするには、コンパイルして拡張子.beamのファイルにする必要があります。
erlc fact.erl
コンパイラは、かなり冗長ですが分かりやすく、Erlangの考え方を理解するのに役立ちます。例えば、変数がバインドされないまま使用される場合には、それが検出されます。
コンパイル後は、factモジュールでエクスポートされているすべての関数を実行できます。これによって、デバッグ時にどの関数が適切に動いていないかを調べることができ、とても便利です。対象環境でErlangエミュレータerlを実行し、次のように入力します。
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false] Eshell V5.7.2 (abort with ^G) 1>
次のようにして、エミュレータ内でコードを再コンパイルできます。
c("fact.erl").
通常、関数startがプログラム実行のmainを表します。
2> fact:start(2,12). Time elapsed for factorial of 12 using 2 parallel processes: 1.45e-4 seconds ok 2>
2つ以上の並列プロセスを使って、大きな整数の階乗を計算してみてください。従来のCPUとマルチコアマシンでは、所要時間に違いがあることが分かるでしょう。
前述のとおり、それぞれの関数も、エクスポートして適切な入力を指定すれば実行できます。
3> fact:compute(2,[123,234,456,345]). 4527984240 3> 4> fact:multiplication([123,234,456,345]). 4527984240 4>
デバッガは次のようにして起動します。
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]
Eshell V5.7.2 (abort with ^G)
1> c("fact.erl",[debug_info]).
{ok,fact}
2> im().
3> ii(fact).
{module,fact}
4> iaa([init]).
true
5> fact:start(2,12).
iで始まる文は、グラフィカルプロセスモニタと、ソースコードを表示する標準的デバッグウィンドウを開始します(図2と図3を参照)。もちろん、これらのウィンドウは、実行中に生成されたプロセスごとにオープンされます。
次のステップ:LYME
これで、並列プロセスを連携し、同時実行させるErlangの仕組みについてご理解いただけたと思います。現在では、Erlangで開発された多くのアプリケーションが実際に使われています。Yahoo! del.icio.us、Facebookのチャットバックエンド、Twitterfall(Twitterのトレンド検索エンジン)、Amazon SimpleDBもそうです。その多くはマルチコアマシンの能力を活用しています。あなたのアプリケーションもその一員に加えましょう。Erlangを本格的に使うなら、LYME(Linux、Yaws、Mnesia、Erlang)ソリューションスタックが、機能的な並列処理ソリューション作成に優れた環境を提供します。


