@twitterこの広告は、90日以上更新していないブログに表示しています。コードは、全体で約2万行です*1。そのうち、ネットワークI/Oやプロトコルに関するコードは約1万行*2で、全体の約半分を占めています。ロジックは残りの半分*3だけで実装されています。この実例から分かりますが、kumofsのような分散アプリケーションを開発するにはI/O周りの実装が大変で、とてつもなく大きな障壁になっています。*4さらに今日では、性能を稼ぐためにマルチスレッド化が必須です。多数のクライアントを少ないリソースで効率よく相手にするには、非同期・イベント駆動型のアーキテクチャも必要になります。おいては、実装のみならず設計も大変です。これに加えてソケットAPIの難解な挙動に対処にしなければならないため、C言語やC++によるネットワークプログラミングは、vimの使いこなしなどと同様に、過酷な「修行」を必要とする分野だったと言えます。mpio(エム・ピー・アイ・オー)は、以上のような問題の解決を目的とした、C++のライブラリです。ソケットとに紐付けられたイベントハンドラ、バッファリング、非同期化されたwritevやsendfile、非同期connect、シグナル、タイマーなど、ネットワークプログラミングで共通して必要になる機能を簡単に利用することができます。Wavyアーキテクチャ(後述)を基盤としており、完全にマルチスレッド化されています。イベントループの実装にはepollとkqueueを利用することができ、コンパイル時に自動的に選択されます。以上の機能に加えて、マルチスレッドプログラミングで必要となる様々なユーティリティを実装しています。内部で利用し、開発を継続してきたmpioライブラリを、このたび独立したライブラリとしてリリースしました。ここではmpioで実装している並列処理のアーキテクチャを紹介し、最後にサンプルコードを紹介します。Downloads(mpio-X.Y.Z.tar.gz)にあります。WavyアーキテクチャWavyアーキテクチャは、1つのイベントループを複数のスレッドで共有し、続けざまに処理していくI/O方式です。紹介していますが、別の図で紹介してみようと思います(クリックで拡大):この図のように、複数のスレッドが順々にイベントループを回していきます。並列して行うことができます。並列して行うことができないので、イベントハンドラがブロックしていると新しいイベントを受け付けられなくなってしまいます。Wavyでは、スレッドの本数が足りる限り並列してイベントを処理することができます。mpioライブラリは、このWavyアーキテクチャを実装しています。ソケット1つに対してイベントハンドラを1つ割り当てて、ソケットにデータが届くとイベントハンドラが呼ばれます。タイマーやシグナルもイベントとして扱うことができ、普通の関数もイベントとして登録できます(=スレッドプールとして使えます*5)。実装上の工夫として、1つのソケットに立て続けに届いたメッセージも、並列して処理できるようになっています(クリックで拡大):図のように旧バージョンの実装では、同じソケットに立て続けに届いたメッセージは並列して処理できませんでした。普通にイベント駆動型のアーキテクチャを実装するとこうなります。新バージョン(現行バージョン)の実装では、これも並列して処理できます。メッセージに依存関係がなければ、並列して処理することで処理時間を短縮できます。サンプルコードシグナル突然地味ですが、シグナルは極めて厄介な存在です。mpioではちょっとした工夫*6を実装しており、シグナルを安全に扱うことができます。lo.run(4);}このプログラムでは、SIGINTが届く(^Cを押す)たびにカウンタを1ずつインクリメントしていきます。これで4本のスレッドが起動し、イベントループが動作します。mpioはもはやマルチスレッドに特化しています。シングルスレッドでは動作できない点に注意してください。2スレッド以上は必須です。タイマーシグナルと同様に、タイマーも簡単に扱うことができます。lo.run(4);}非同期connectconnect(2)を非同期で行うことができます。タイムアウト付きのconnectは自前で実装すると非常に面倒ですが、mpioを使えば簡単に使えます。lo.run(4);}イベント駆動read・非同期write先のコードはソケットを接続した段階で終わっています。ソケットをイベントループに登録すると、データが届いたときにイベントハンドラが呼ばれるようになります。これでイベント駆動型のreadを行うことができます。イベント駆動型のアーキテクチャでは、処理が長くブロックすると並列性が落ち、性能が出ません*7。そこでイベント駆動型のアーキテクチャでは、往々にしてwriteを非同期化することで性能の向上を図ります。内部に隠蔽されていますが、その実体は、マルチスレッド化されたイベント駆動型のアーキテクチャになっています。複数のホストに同時にデータを送ると、並列して処理されます。writeを非同期化すると、バッファを解放するタイミングが難しくなります。これに対してmpioでは、writeメソッドにstd::auto_ptrやmp::shared_ptrを渡せるようになっています。writeが完了するとこれらの参照が解除され、メモリが解放されます。機能を利用できるように抽象化するヘッダも含んでいます。他のユーティリティライブラリは、ヘッダをincludeするだけで利用できます。mpioのリリース情報は、このブログで順次お知らせしていく予定です。現状、ドキュメントはほとんどありません。