読者です 読者をやめる 読者になる 読者になる

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

erlang で書かれた Wiki

Erlangで書かれたWiki - スコトプリゴニエフスク通信 から http://www.sics.se/~joe/tutorials/wiki/wiki.html を見て、とりあえず動かしてみんだけど、

$ ab -c 10 -n 10000 "http://localhost:4992/wiki/showPage?node=home"

Requests per second:    1650.08 [#/sec] (mean)

速いなあ。

ソース行数はこんな。

$ find -name '*.erl' | xargs wc -l
   92 ./wiki-14.0/diff.erl
  119 ./wiki-14.0/find.erl
  774 ./wiki-14.0/wiki.erl
   42 ./wiki-14.0/wiki_convert.erl
  252 ./wiki-14.0/wiki_format_txt.erl
  108 ./wiki-14.0/wiki_split.erl
   52 ./wiki-14.0/wiki_templates.erl
   73 ./wiki-14.0/wiki_to_html.erl
   80 ./wiki-14.0/wiki_utils.erl
  190 ./pico-11.0/pico_http_server.erl
  147 ./pico-11.0/pico_socket_server.erl
   45 ./pico-11.0/pico_test.erl
  226 ./pico-11.0/pico_utils.erl
 2200 total