erlang で並列 HTTP request

まだ erlang の基礎もロクに勉強してないというのに、単に面白そうだから、という理由で並列プログラミングに手を出してみた。
HTTP get を複数の URL に対して並列で発行する。全体の構造は以下のようなもので。

  • main
    • manager プロセスを作成
    • 引数で受けた URL のリストから、ひとつの URL ごとに worker プロセスを作成
  • worker
    • URL を HTTP GET して、結果を manager プロセスにメッセージ送信
  • manager
    • workerプロセスから受けたメッセージを出力

erlang、さわって二日目だけどかなり取っ付きやすい印象。
, で区切ったのが順番に実行されるし、printf デバッグもできるし。
Erlangは関数型だけど難しくない: みかログ には全面的に同意。

-module(cohttp).
-compile(export_all).

create_worker( Url, Manager ) ->
    spawn(?MODULE, worker, [ Url, Manager ]).

worker( Url, Manager ) ->
    erlang:display(["starting worker", Url]),
    { Flag, Result } = http:request(Url),  % HTTP get 発行
    case Flag of
        ok    -> { { _, Status, _ }, _, _ } = Result;  % パターンマッチで Status 取り出し
        error -> Status = Result
    end,
    Manager ! [ Url, Status ].        % Manager にメッセージ送信 

create_manager() ->
    spawn(?MODULE, manager, []).

manager() ->
    receive
        % 受信したメッセージをパターンマッチ
        [ Url, Status ] -> io:format("~s is ~w~n", [ Url, Status ]),
                           manager()           % loop
    end.

main( UrlList ) ->
    Manager = create_manager(),
    [ create_worker( Url, Manager ) || Url <- UrlList ].

実行結果。

Eshell V5.5.4  (abort with ^G)
1> c(cohttp).
{ok,cohttp}
2> cohttp:main(["http://www.google.com", "http://www.yahoo.co.jp", "http://badhost/"]).
["starting worker","http://www.google.com"]
["starting worker","http://www.yahoo.co.jp"]
["starting worker","http://badhost/"]
[<0.39.0>,<0.40.0>,<0.41.0>]
3> 
http://badhost/ is nxdomain
http://www.google.com is 200
http://www.yahoo.co.jp is 200