Erlang プログラミング入門: 第 2 回 高度な特徴や機能を使用する

Erlang は、主に並行システムの開発と分散システムの開発に使用される、多目的のプログラミング言語です。この連載の第 1 回では、Erlang の概要、そして Erlang の関数型プログラミング・スタイルと他のプログラミング・パラダイム (命令型、手続き型、そしてオブジェクト指向のプログラミングなど) との違いを説明しました。第 2 回では基本的な関数から並行プログラミング、プロセス、そしてメッセージングへと話題を移し、高度な特徴や機能のいくつかを使用してみます。これらの高度な特徴や機能が連動することによって、Erlang の強力な特徴である分散プログラミングをサポートします。

Martin Brown, Professional Writer, Freelance Developer

author photoMartin Brown は過去 8 年以上プロのライターとして活躍してきました。彼はさまざまな話題に関して数多くの本や記事を執筆しています。専門領域は広く、無数の開発言語やプラットフォーム (Perl、Python、Java、JavaScript、Basic、Pascal、Modula-2、C、C++、Rebol、Gawk、Shellscript、Windows、Solaris、Linux、BeOS、Mac OS X その他) から、Web プログラミング、システム管理やシステム統合にまでわたります。彼は ServerWatch.com と LinuxToday.com、そして IBM developerWorks に頻繁に寄稿しており、また Computerworld や The Apple Blog などのサイトの他、Microsoft の SME (Subject Matter Expert) にもブロガーとして頻繁に寄稿しています。彼の連絡先は、彼の Web サイト http://www.mcslp.com/ です。



2011年 6月 24日

並行プログラミング

従来の関数型プログラミング言語でのプログラミングで常に必要とされてきたのは、複数のプログラムを同時に実行するのではなく、単一のプログラム内で複数のプロセスを同時に実行する機能を実装するように方法を変えることです。このような並行性 (あるいはマルチスレッド化) に伴う問題は、情報を更新するために使用するスレッドが、現在処理中のデータと情報だけに作用することを確実にしなければならないという点です。例えば、1 つのファイルを更新するプロセスが、そのファイルに対して何度も実行されるのは望ましくありません。そうなると、プロセスを繰り返す過程でファイルが壊れてしまう危険があるからです。

Erlang が取っている手法では、すべてのプログラムは同時に実行可能であり、コンポーネント (関数およびモジュール) は決してデータを共有しません。データを共有する代わりに、メッセージを使用してコンポーネント間でデータを交換します。メッセージを使用して、個々のコンポーネントによるデータの変更を制限すれば、データの同時変更に関する問題の解消につながります。つまり、データを直接変更するのではなく、データを変更するにはメッセージを送信するようにすることで、個々の変更を切り分け、同時更新をより困難にするというわけです。また Erlang は、処理が失敗することを前提に作られているため、Erlang によるシステムはエラーに対処し、必要な場合にはエラーからリカバリーできるようになっています。

Erlang 内部では、並行性の問題に対処するために、プロセスと呼ばれる小さくて軽量の実行可能プログラムを作成します。C などの他の主要な言語とは異なり、Erlang のプロセスはネイティブ・オペレーティング・システムのプロセス上に作成されるわけでも、さらにはスレッド・モデルに基づいて作成されるわけでもなく、Erlang 仮想マシンによって内部で作成されて管理されます。そのため、各プロセスは、メモリーと CPU の要件という点で、ネイティブ OS スレッドよりも遥かに軽量になります。さらに、Erlang はこれらの多数の小さなプロセスを自動的に作成して使用することによって動作するため、比較的単純なプログラムであっても、何千あるいは何百万ものプロセスを実行するのが通常です。

Erlang には並行性モデルが組み込まれているため、Erlang が動作する仕組みにおいて、この莫大な数のプロセスを管理することが重要な部分となってきます。Erlang には、プロセス間でデータを送信するためのメッセージング・システムも組み込まれています。このメッセージング・システムは、現在実行中のプロセスの数によらず、極めて効率的な方法でメッセージをプロセスに分散するように設計されています。メッセージ実装による副次効果は、メッセージを内部で送信できるだけでなく、ネットワーク全体にまで送信できることです。そのため、Erlang は複数のインスタンスでメッセージを共有することによって、複数のマシンを範囲とした分散プログラミングをサポートすることができます。


プロセス

Erlang のプロセス・システムは極めて軽量であることから、プロセスは至って単純かつ容易に作成することができます。それは、オーバーヘッドがないため、オーバーヘッドに伴う影響を心配する必要がほとんどないからです。これは、アプリケーションを支援するためならば、どのような理由であっても新しいプロセスを作成できることを意味します。

実際にプロセスを作成するには、PID = spawn(module, function, arguments) という形で組み込み関数 spawn() を呼び出します。ここで、module はモジュール名、function は関数名、arguments は関数に渡す引数のリストです。戻り値 (上記の例では PID) はプロセス ID です。

例えば、連載の前回の記事で作成したフィボナッチ関数を新しいプロセスとして呼び出すとしたら、PID = spawn(fib,printfibo,[10]) のようにします。

spawn() に渡す最後の引数は、関数を直接呼び出すときに使用するような単一の引数ではなく、1 つの要素だけが含まれるリストであることに注意してください。呼び出しの結果として作成される新しいプロセスは、あたかも fib:printfibo(10) が呼び出されているかのように、この関数を実行します。

spawn() によって作成される新規プロセスは、正常終了する (つまり、エラーがない) か、異常終了する (何らかの障害が発生する) まで実行され続けます。

実際のプロセスの作成自体は、呼び出している関数が存在しないとしても、失敗することは決してありません。したがって、プロセスを作成するコードをテストする必要はありません。プロセスが作成された後に Erlang シェルで発生したエラーは、エラー・ロガーによって処理されて記録されます。エラー・ロガーは、エラーのレポート作成を処理する組み込みプロセスです。

標準的な使用方法では、プロセスは並行性をサポートするために使用されます。前述のフィボナッチの例では、別のプロセスで printfibo() 関数を実行したところ、有用な戻り値は生成されませんでした。けれども、新しいプロセス (例えば基本となる fibo() 関数など) を作成して、2 つのプロセスの間で情報を受け渡せるようにしたとしたらどうなるでしょうか。

このようなやりとりを処理するのが、組み込みメッセージング・システムです。


メッセージング

Erlang のメッセージング・システムも、Erlang 実行環境に組み込まれています。このメッセージング・システムがプロセス・システムと連携して、効率的にデータおよびメッセージを交換できるようにします。

各プロセスには「メール・ボックス」があり、他のプロセスはそこにメッセージを送信することができます。メッセージは、送信された順でメール・ボックスに保管されます。つまり、あるプロセスから別のプロセスに A と B という 2 つのメッセージを送信すると、メール・ボックス内ではメッセージ A が最初に表示され、メッセージ B が 2 番目に表示されるということです。プロセス・システムに備わった並行性により、1 つのプロセスに対して複数のプロセスから送信されたメッセージには特定の順序付けはありません。同じプロセスから送信されたメッセージの間でのみ順序が付けられます。

プロセスにメッセージを送信するには、通信したいプロセスのプロセス ID を知る必要があります。その上で、Pid ! Message という形でメッセージを送信します。ここで、Pid はプロセス ID、Message は Erlang の任意のデータ型です。

プロセス内でメッセージを受信するには receive ステートメントを使用します。receive ステートメント内ではパターン・マッチングを利用して、メッセージの内容を基に処理内容を決定します。パターン・マッチングに成功すると、メール・ボックスからメッセージが受信され、メッセージの引数がそのパターン・マッチに含まれる変数にバインドされて使用可能になり、対応する節が実行されます。

リスト 1 に、store というアトムと値を指定したメッセージに対するマッチングの例を記載します。

リスト 1. receive ステートメントを使用してプロセス内からメッセージを受信する
receive
    {store, Value} -> store(Value),
    {get, Value} -> get(Value)
end

上記のサンプル・コードは、パターン・マッチングを使用してアトムと左側の変数を突き合わせた後、右側の処理を実行します。この例の場合、その処理に該当するのは、メッセージの内容に基づいて値を保管し、値を取得することです。

receive ステートメントはプロセス内での実行を一時中断することで、必ずプロセスが新しいメッセージの到着を待ってから処理を実行するようにします。その典型例は、複数のプロセスで共有される可能性のある変数を保管するという基本的な操作です。

アプリケーション内では、receive ステートメントをループの一部として使用し、プロセスに対して送信された新しいメッセージを漸進的に読み取って個々の操作を実行するというのが通常ですが、第 1 回 (「参考文献」を参照) で用いたフィボナッチの例でわかるように、Erlang には従来の意味でのループはありません。代わりに、その関数自体を呼び出して次のメッセージを処理する関数を作成します (リスト 2 を参照)。

リスト 2. 自己を呼び出して次のメッセージを処理する関数
dbrequest() ->
    receive
        {store, Value} -> store(Value),
        {get, Value} -> get(Value)
    end

従来の並行環境では、セマフォーなどのソリューションを使用して、変数が「使用中」であるのか、更新可能であるのかをプロセスが判断できるようにします。多くの環境では、同じ値を更新しようとする各プロセスはセマフォーによって待機することになるため、プログラムの実行が遅れる可能性があります。一方、Erlang では個々の処理を 1 つのプロセス内にまとめて包含し、メッセージングを使用して更新を処理することができます。メッセージは順次受信されるため、これらのメッセージを順に処理することで、それぞれの処理を個別に実行することができます (図 1 を参照)。

図 1. メッセージングを使用した、単一の値での更新処理
データのフローを示す図。値の保管、値の読み取り、値の更新、さらに値の更新が行われた後、フローは receive へと続き、receive によってデータの作成、取得、更新、削除などの操作が行われます。

この基本的な並行性およびメッセージング構造は、さまざまなアプリケーションのベースとなっています。例えば Facebook では、Facebook メッセージングにメッセージ環境を使用しています。また CouchDB (MochiWeb をベースに Web にインターフェースを提供しているドキュメント・ベースのデータベース) は、プロセスおよびメッセージング・システムを利用して、データベースの更新と応答が正常に処理されるようにしています。そのため、他のデータベースでは悩みの種となりがちな通常の並行更新の問題がありません。

メッセージングは、特に並行処理との組み合わせにより、さまざまな場所から複数のリクエストが送信されるとしてもプログラムが情報を順次処理されるようにします。このことは、プロセス内の情報の破損や破棄を心配することなくデータおよび処理を共有できるという点で、他の言語での一般的な並行プログラミングが抱える主要な問題から逃れられることになります。つまり、ほとんどの並行プログラミングの問題に存在する主な悩みの種が 1 つ排除されるということです。

けれども並行性が有効なのはここまでで、ソリューションをスケールアップしてパフォーマンスを改善するという問題を解決するとなると、また別の話です。これは、最近のネットワークと Web アプリケーションでは尚更のことで、最終的には複数のサーバーが必要になってきます。幸い、Erlang には分散プログラミングの問題に対するソリューションもあります。


分散プログラミング

Erlang での分散プログラミングは、単純なネットワーク・サーバーとメッセージング・システムの組み合わせがベースとなります。メッセージング・システムは、この記事ですでに説明したように、メッセージを送受信するためのメカニズムを提供するだけでなく、さらに重要なことに、ネイティブ RPC (Remote Procedure Call: リモート・プロシージャー・コール) や Web サービスなどの環境でサポートされるような RPC をサポートするメカニズムを提供します。

注目に値する点は、分散とは、必ずしも異なる複数のマシンを意味するわけではなく、互いにやりとりして情報や処理を共有する必要がある 2 つの異なる Erlang アプリケーションを意味する場合もあることです。Erlang は一般的な用途においては、通信対象のシステムを識別するだけで、システムがローカルであるか、リモートであるかを区別しません。

分散プログラミングに取り掛かるには、まず、Erlang を起動して、Erlang の各インスタンスに一意の名前を付ける必要があります。この一意の名前が識別時に使用されて、Erlang の指定のインスタンスにメッセージを送信できるようになります。コマンドラインから Erlang を使用している場合、名前を設定するには sname コマンドライン・オプションを使用することができます (リスト 3 を参照)。

リスト 3. sname コマンドライン・オプションを使用する
$ erl -sname one
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [rq:1] [async-threads:0]

Eshell V5.7.5  (abort with ^G)
(one@mammoth)1>

プロンプトが変更されて名前とホスト名を示すようになることに注目してください。この名前とホスト名のセットはノードに対する一意の ID となり、Erlang 内でノードを識別するため、そしてノード間で通信するために使用することができます。

ここで、Erlang シェルのインスタンスをもう 1 つ立ち上げるとしたら、そのインスタンスには異なる名前を設定することができます (リスト 4 を参照)。

リスト 4. 異なる名前を設定する
$ erl -sname two 
Erlang R14B (erts-5.8.1) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe] 
[kernel-poll:false]

Eshell V5.8.1  (abort with ^G)
(two@mammoth)1>

両方のノードが稼働中になったところで、net_adm:ping() を使用して、一方のノードが他方のノードと通信できるかどうかをテストすることができます (リスト 5 を参照)。

リスト 5. net_adm:ping() を使用して一方のノードが他方のノードと通信できるかどうかをテストする
(one@mammoth)3> net_adm:ping('two@mammoth').
pong

これで、インスタンス one がインスタンス two と通信できることがわかりました。

2 つのプロセス間でメッセージを送信するには、メッセージング演算子を変更して、受信側のプロセス ID だけでなくノード名を含めるようにします。例えば、プロセスが basic という名前で登録されていて、リスト 5 のコードを使用してメッセージを送信するとしたら、最初に作成した Erlang のインスタンスのシェルには、{ basic, 'two@mammoth'} ! { self(), "message" } と入力することができます。

2 番目のホストでカレント・プロセス (つまり、シェル) を「basic」として登録し、メッセージを取得すれば、メッセージ・データを出力することができます。カレント・プロセスの登録は、インスタンス one でメッセージを送信する前に行わなければなりません (リスト 6 を参照)。

リスト 6. カレント・プロセスを登録する
(two@mammoth)1> register(basic,self()).
true

今度は、メッセージを出力するための receive ステートメントを作成します (リスト 7 を参照)。

リスト 7. メッセージを出力するための receive ステートメントを作成する
(two@mammoth)2> receive                             
(two@mammoth)2> {From,Message} -> io:format(Message ++ "~n")
(two@mammoth)2> end.
something
ok

Erlang の 2 つのインスタンスの間で、問題なくメッセージを送信することができました。これらのインスタンスが同じマシン上ではなく、別々のマシン上に存在するとしても同様に簡単なことです。2 つのマシン間でメッセージを送信できるとなれば、あらゆる類のデータを送受信するには、プロセス ID とノード名がわかっていさえすればよいからです。

さらによく使われる RPC については、Erlang は rpc:call(Node, Module, Function, Arguments) の形で rpc:call() 関数もサポートします。

この関数は、リモート・ノードを呼び出して、特定のモジュールと関数を指定の引数で実行し、その結果を呼び出し側に返します。rpc モジュールには、同期呼び出し、非同期呼び出し、およびブロッキング呼び出しを可能にする拡張機能が含まれています。この場合、関数を直接呼び出すことになるため、多数のクライアントが同時に稼働していると、並行性の問題が発生する可能性があります。従って、メッセージング・モデルと比べると理想的ではないかもしれませんが、それはアプリケーション次第です。


MochiWeb を使用する

MochiWeb は Erlang をベースとする完全な HTTP Web スタックです。MochiWeb は、この記事で説明してきた Erlang の特徴の多くを利用します。例えば、高いレベルの並行性でハイパフォーマンスを実現するために、メッセージングとプロセスが使用されています。MochiWeb はプロセス・システムを利用して並行性をサポートし、メッセージの力を借りて、リクエストを処理して結果を集積します。

MochiWeb 自体は、基本的なフレームワークを素早く作成できるようにするためのコードと一連のスクリプトの組み合わせです。MochiWeb で作成したフレームワークから、独自のアプリケーションを構築し、拡張することができます。この最後のセクションで、MochiWeb の使い方、新しい Web サーバー・アプリケーションのセットアップ方法、そして独自のアプリケーションをサポートするように拡張する方法を説明します。

MochiWeb を導入するのに最も簡単な方法は、GitHub からソース・コードを取得することです。それには、git コマンドを使用するか、または GitHub Web サイトに用意されているダウンロード可能なパッケージを使用することができます (「参考文献」を参照)。

git を使用してソースを取得する場合には、$ git clone https://github.com/mochi/mochiweb.git を実行します。

このコマンドによって、カレント・ディレクトリーに mochiweb というディレクトリーが作成されます。MochiWeb を使用するには、ソースをビルドする必要があります。それによって、新しい MochiWeb アプリケーションを作成できるように MochiWeb が準備されます。

ソースをビルドするにはまず、mochiweb ディレクトリーで make を実行します (リスト 8 を参照)。

リスト 8. リソースをビルドする
$ cd mochiweb $ make
==> mochiweb (get-deps)
==> mochiweb (compile)
Compiled src/mochiweb_sup.erl
Compiled src/mochifmt.erl
Compiled src/mochiweb_charref.erl
Compiled src/mochiweb_request_tests.erl
Compiled src/mochifmt_records.erl
Compiled src/mochiweb_socket.erl
Compiled src/mochiweb_app.erl
Compiled src/mochiweb_io.erl
Compiled src/mochifmt_std.erl
Compiled src/mochiglobal.erl
Compiled src/mochiweb_socket_server.erl
Compiled src/mochijson.erl
Compiled src/mochihex.erl
Compiled src/mochiweb_html.erl
Compiled src/mochiweb_multipart.erl
Compiled src/mochilogfile2.erl
Compiled src/mochiweb_cover.erl
Compiled src/mochiweb_util.erl
Compiled src/mochitemp.erl
Compiled src/reloader.erl
Compiled src/mochinum.erl
Compiled src/mochiweb_headers.erl
Compiled src/mochiweb_skel.erl
Compiled src/mochiutf8.erl
Compiled src/mochiweb_echo.erl
Compiled src/mochiweb_acceptor.erl
Compiled src/mochiweb_http.erl
Compiled src/mochijson2.erl
Compiled src/mochiweb_cookies.erl
Compiled src/mochiweb.erl
Compiled src/mochiweb_mime.erl
Compiled src/mochilists.erl
Compiled src/mochiweb_response.erl
Compiled src/mochiweb_request.erl

これで、mochiweb ソースがコンパイルされました。この後独自の Web サーバーを構築する際に利用することが可能なサンプルのアプリケーション・フレームワークを作成するために、もう一度 make を使用して新規プロジェクトのディレクトリーを作成します。PROJECT はプロジェクトとディレクトリーの名前になり、PREFIX は新規 PROJECT ディレクトリーが作成されるディレクトリー名になります。例えば、mywebserver というプロジェクトを作成する場合は、$ make app PROJECT=mywebserver PREFIX=../ とします。

上記のコマンドによって、新しい MochiWeb アプリケーションが親ディレクトリー (つまり、mochiwebと同じレベルにあるディレクトリー) 内に作成されます。

新しく作成されたディレクトリーは、デフォルトで (すべてのインターフェースで) ポート 8080 をリッスンする基本的な Web サーバーです。アプリケーションをビルドするために、再び make を実行し、MochiWeb コンポーネントと個々のアプリケーションが確実にコンパイルされるようにします。

$ cd ../mywebserver
$ make

最後に start-dev.sh スクリプトを実行して、この基本的なアプリケーションを実行してください。このスクリプトは大量の出力を生成します。その出力はすべて、Web サーバーを処理するために作成中の個々のプロセスの「進行状況レポート」です。出力にエラーが報告されていなければ、Web サーバーは稼働している状態になっています (リスト 9 を参照)。

リスト 9. 稼働中の Web サーバー
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [rq:1] [async-threads:0]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.42.0>},
                       {name,alarm_handler},
                       {mfa,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.43.0>},
                       {name,overload},
                       {mfa,{overload,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.41.0>},
                       {name,sasl_safe_sup},
                       {mfa,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.44.0>},
                       {name,release_handler},
                       {mfa,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
         application: sasl
          started_at: mywebserver_dev@localhost
Eshell V5.7.5  (abort with ^G)
(mywebserver_dev@localhost)1> ** Found 0 name clashes in code paths 

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,crypto_sup}
             started: [{pid,<0.54.0>},
                       {name,crypto_server},
                       {mfa,{crypto_server,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
         application: crypto
          started_at: mywebserver_dev@localhost
** Found 0 name clashes in code paths 

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,mywebserver_sup}
             started: [{pid,<0.59.0>},
                       {name,mywebserver_web},
                       {mfa,
                           {mywebserver_web,start,
                               [[{ip,{0,0,0,0}},
                                 {port,8080},
                                 {docroot,
                                     "/root/mybase/mywebserver/priv/www"}]]}},
                       {restart_type,permanent},
                       {shutdown,5000},
                       {child_type,worker}]

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
         application: mywebserver
          started_at: mywebserver_dev@localhost

=PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.77.0>},
                       {name,timer_server},
                       {mfa,{timer,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,1000},
                       {child_type,worker}]

新しい Web サーバーにアクセスできるかどうかを試すには、Web ブラウザーを開いてください。Web サーバーが同じマシン上にある場合には、Web ブラウザーで http://localhost:8080/ を指定します。すべてが適切に動作していれば、「It Worked (成功です)」というタイトルと「webserver running (Web サーバーの実行中)」というメッセージが示されたページが表示されるはずです。

新規サーバーを変更したい場合には、アプリケーション・ディレクトリー内にある src/mywebserver_web.erl ファイルを編集します。このファイルには、Web サービスを実行およびサポートするためのコア・コードが含まれます。

プロセスのコアは、loop() 関数です。この関数は、メインの MochiWeb システムがリクエストを受信するたびに呼び出されます。関数に提供する引数は、リクエスト構造体 (リクエストのタイプ、パス、本体データが含まれます) と DocRoot の 2 つです。後者が必要となる理由は、サーバーはデフォルトで、ファイルシステムから要求されたファイルを指定されたドキュメント・ルート内に提供するためです。リクエストのプロセスは、2 つのフェーズで行われます。最初のフェーズでは、case 文によってリクエスト・タイプ (GETPOST など) が抽出されます。次に、2 番目の case 文によってリクエストのパスが識別されます。

一方のノードでのパスが特定のレスポンスをトリガーするようにするためには、Erlang のパターン・マッチングを使用することができます。リスト 10 に一例として、サーバー上のパス /hello にアクセスすると、「Hello world」というフレーズを返すように変更したコードを記載します。

リスト 10. Erlang でのパターン・マッチング
loop(Req, DocRoot) ->
    "/" ++ Path = Req:get(path),
    try
        case Req:get(method) of
            Method when Method =:= 'GET'; Method =:= 'HEAD' ->
                case Path of
                    "congrat" ->
                        Req:ok({"text/html", [],["<h1>Congratulation
</h1>"]});
                    "hello" ->
                        Req:ok({"text/plain",[],["Hello world"]});
                    _ ->
                        Req:serve_file(Path, DocRoot)
                end;
            'POST' ->
                case Path of
                    _ ->
                        Req:not_found()
                end;
            _ ->
                Req:respond({501, [], []})
        end
    catch
        Type:What ->
            Report = ["web request failed",
                      {path, Path},
                      {type, Type}, {what, What},
                      {trace, erlang:get_stacktrace()}],
            error_logger:error_report(Report),
            %% NOTE: mustache templates need \ because they are not awesome.
            Req:respond({500, [{"Content-Type", "text/plain"}],
                         "request failed, sorry\n"})
    end.

ファイルを編集した後は、必ずアプリケーションをリビルドしてから、start-dev.sh スクリプトを使ってアプリケーションを再起動してください。

アプリケーションを再起動してから http://localhost:8080/hello を指定して Web サーバーの URL にアクセスすると、hello world メッセージが表示されるはずです。

これは簡単な例ですが、基本的な REST サービスのサポートといった新しい機能は、POST または PUT リクエストを検索し、文書の本体を処理し、そして情報を保管することで簡単に追加することができます。作成されたプロセスとメッセージングを使用すれば、サーバーからのリクエストをキューに入れて、情報を保管、更新、および取得することも可能です。


まとめ

Erlang の歴史は、電話交換機の環境で育まれてきました。つまり、この言語のコア機能は、他のほとんどの言語とはまったく異なる環境で開発されてきたということです。この言語では、多数の処理 (例えば、通話など) を同時に行えるようにするために、複数のプロセスを実行および作成することに関する問題への対処がなされています。

新しいプロセスを作成し、これらのプロセスの間で通信を行っても、他の部分に影響することも、プロセス間で情報を共有するための複雑なセマフォー・システムを必要とすることもなく、その仕組みが単純化されているのは、組み込みのメッセージング・システムが使用されているおかげです。メッセージングは順次行われるため、各プロセス間での通信を簡単に扱うことができます。さらに、メッセージング・システムは Erlang インスタンスおよびネットワーク全体にわたって動作することから、マシン間の通知が単純かつ直接的になります。

Erlang の機能の多くを結集した MochiWeb は、ハイパフォーマンスで極めてスケーラブルな Web サーバー・ソリューションになるだけでなく、ほんのわずかな作業で、追加の機能をサポートするように拡大および拡張することもできます。

参考文献

学ぶために

  • Erlang Web サイト: このプログラミング言語についての詳細を調べてください。
  • ウィキペディアの Erland に関する記事: Erland の歴史をより深く学んでください。
  • Erlang and OTP in Action』(Martin Logan、Eric Merritt、Richard Carlsson 共著、Manning Publications) は、OTP フレームワークを使用して、Erlang で実用的なアプリケーションを作成することに興味を持つ開発者のための一冊です。
  • Erlang プログラミング』(Francesco Cesarini、Simon Thompson 共著、オライリー・ジャパン) では、並行性、耐障害性、そして素早い応答が必要不可欠な場合に理想的なプログラミング言語、Erlang について詳しく説明しています。
  • プログラミング Erlang』(Joe Armstrong 著、オーム社) では、ネットワークやハードウェア障害にも耐える、信頼性に優れたアプリケーションを Erlang プログラミング言語で作成する方法を説明しています。
  • developerWorks podcasts: ソフトウェア開発者向けの興味深いインタビューとディスカッションを聞いてください。
  • Technical events and webcasts: developerWorks Live! briefings で時代の流れに乗ってください。
  • Twitter での developerWorks: developerWorks をフォローして最新ニュースを入手してください。
  • 興味深いイベント: 世界中で近日中に予定されている IBM オープンソース開発者を対象とした会議、見本市、ウェブキャストをチェックしてください。
  • developerWorks Open source ゾーン: オープンソース技術による開発、そして IBM 製品でオープンソース技術を使用するときに役立つ広範囲のハウツー情報、ツール、プロジェクト・アップデート、そして人気の高い記事とチュートリアルを調べてください。
  • developerWorks Web architecture ゾーン: さまざまな Web ベースのソリューションを話題にした記事を調べてください。
  • developerWorks オンデマンド・デモ: 無料のオンライン・デモで、IBM およびオープンソースの技術と製品機能を試してみてください。

製品や技術を入手するために

  • MochiWeb: 軽量の HTTP サーバーを構築するための Erlang ライブラリーは、GitHub でホストしています。
  • Erlang: Erland プログラミング言語をダウンロードしてください。
  • The Apache CouchDB Project: Erlang で作成され、MochiWeb HTTP サーバーを利用する CouchDB は、Apache から入手できます。
  • IBM ソフトウェアの試用版: 試用版ソフトウェアを使用して、次のオープンソース開発プロジェクトを革新してください。ダウンロード、あるいは DVD で入手できます。

議論するために

  • developerWorks コミュニティー: ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, XML
ArticleID=681601
ArticleTitle=Erlang プログラミング入門: 第 2 回 高度な特徴や機能を使用する
publish-date=06242011