|
|
||
継続ベースのウェブアプリケーションフレームワークとかたまに見かけたりするんですが、継続をセッション管理に使うとかは大したメリットがなくて、スケーラビリティの確保のために有益であると考えてます。2009年にもなって我々はセッション管理に困ってたりはしないんです。
Webアプリケーションにおける処理時間の殆どは何らかのI/O待ちだったりするので
という実装にすることで、並列度を上げることが出来ます。停止している間に他の処理ができるようになるわけですね。コルーチンを使うことで、この「停止と再開」を実現することができます。最近、コルーチン使ってクローラのロードアベレージを十分の一ぐらいにしました。これは特に問題なく動いていて、この高速化アプローチを段階的にウェブアプリケーションにも応用していこうと考えています。ウェブアプリケーション構築に必要な主要なコンポーネントを非同期化する必要があります。
言語に関係なく、大体三つぐらいに集約されるような気がします。
あるいは、これらを組み合わせて非同期化を実現することができます。
1はイベントベースとかイベントドリブンとか言われると思います。callbackを登録してイベントループを回す。イベントフレームワークってのはどれも大体一緒な感じで、イベントリスナ(selectとかepollとか)に監視対象(ファイルハンドルとか)を突っ込んでイベントが起きたら(readable/writableになったら)、callback関数が呼ばれる。JavaScriptでDOMスクリプティングと似たようなもんだ。2はRPCとかそんなん。PerlにPOEというイベントフレームワークがありますが、容易にノンブロック化できないようなケースでは別プロセスを立ち上げて通信したりします。純粋に計算処理で時間がかかるような場合はネットワーク越しの別のマシンにやらせることができるというメリットがある。3の場合でもコルーチンを再開するタイミングを制御するために、1と同様にI/O監視を局所化する必要がある。タイマーで適当なタイミングで戻してもいいけどコンテキスト切り替えのコストが無駄になる。
非同期化にコルーチンを使うメリットは、既存のコードを殆ど変更しなくて済むことだ。1は全部イベントドリブンで書き直さないといけない。POE::Component::*を見よ。頑張りすぎだ。
http://search.cpan.org/search?query=POE%3A%3AComponent&mode=all
2はブロックしそうな箇所をプログラマが意識して切り離す必要がある。データの受け渡しに工夫しないといけない。複雑なオブジェクトを受け渡すならデータをシリアライズ/デシリアライズするコストがかかる。スレッド使って上手いことやれば高速化できるんだろうが、俺は知らないしやりたくない。
3は既存のコードがそのまま使える。手順はブロックしそうな箇所(並列化したい箇所)をコルーチン化するだけだ。I/O waitが発生する箇所で別のコルーチンに処理が移り、準備が出来たら再開される。
ということを昨日飲み屋で話したんだけど、そんな上手くいくわけ無いとか言われた。案外上手くいってるので是非試してみて欲しい。少なくともあなたのウェブアプリケーションをLispで書き直すよりは現実的だ。PerlではCoroというモジュールでコルーチンを実現できる。RubyではRuby1.9のFiberを使ったNeverBlock、Pythonではeventletというのがあるらしいよ。
I/O multiprexerがfiberのスケジューラとして動くようにするためにちょっとしたコツが必要ですが、処理をシーケンシャルに記述できるというのは開発効率だけでなくコードの見通しの上でも有益なのでもっと広まって欲しいですね。