非同期I/Oはインターネット上の文献を読んでいると、ノンブロッキングI/Oと同じだと解釈されていることが多い。同僚もノンブロッキングI/Oと非同期I/Oは同じだと話していたけど、この辺の話はあまり詳しくないから納得できなかったが、本当にそうなんだろうか。本記事では、非同期I/O、ノンブロッキングI/Oをの違いを整理することを主眼として、関連する同期I/O、ブロッキングI/O、I/O多重化などI/O周りのあやふやなに知識を焼きなおそうと思う。結論から結論からいうと、ブロッキングI/Oと同期I/Oは同じであるが、ノンブロッキングI/Oと非同期I/Oは違うものと自分は判断した。I/O)ブロッキングI/O(同期I/O)ではI/O処理時に対象のファイルディスクリプタが準備完了になっていない場合、ブロック状態、つまりプロセスはシステムコールの返答待ち状態になり張り付く。その間プログラムの処理が進むことはない。以下は、ブロッキングI/Oのユーザーモードとカーネルモードの遷移を表す。カーネルモードにコンテキストが切り替わり、システムコールの実行が完了すると元のユーザモードにコンテキストが戻り、ブロック状態からも解放される。I/O”から引用させて頂いたものである)ノンブロッキングI/OノンブロッキングI/OではI/O対象のファイルディスクリプタの準備完が了していないことをアプリケーション側に伝えるため即座にエラーが返る(errnoにEGAINが格納されて返ってくる)。一般に、O_NONBLOCKフラグを利用してノンブロッキングモードを宣言するが、この時プロセスはブロック状態にならず、CPUを他の処理に回すことができるためI/O待ち時間を有効活用できる。エラーはアプリケーション側でハンドリングしてリトライするタイミングを定義する必要がある。ノンブロッキングI/Oはソケットなどのネットワークに用いられるI/OモデルでディスクI/Oには使わない。C10K問題の対策としてノンブロッキングI/O+イベントループモデルを採用することでシングルスレッドで複数の接続を処理する方法がある。I/O)I/O処理が完了したタイミングで通知するI/Oモデルを非同期I/Oという。非同期I/Oは、通知はシグナルもしくはコールバックによって行われ、通知があるまではアプリケーション側で他の処理を進めることができる。プロセスがブロック状態にならない点ではノンブロッキングI/Oと一緒だが、非同期I/OはI/Oの処理が完了したら通知をし、ノンブロッキングI/OはI/O処理が可能な状態にないことをエラーで通知するので動きは異なる。I/Oは処理がすぐできない時は処理が完了するまでバックグラウンドで待機して、終了したタイミングで通知を返す方式(通知が来たら既に処理が終わっている)。Multiplexing)I/O関連の調査をしていると必ず出てくるのがI/Oの多重化。このI/O多重化とはpoll()、select()、epollシステムコールを利用して、複数のファイルディスクリプタを1つのプロセスで管理すること。これらのシステムコールはファイルディスクリプタの状態変化を監視できるため、複数のファイルディスクリプタのいずれかが入出力準備が完了したかわかる。select、poll、epollの違いは以下の通り。selectselectはI/Oを多重化するためのシステムコールの1つ。監視対象のファイルディスクリプタn個をループの中で1つずつ状態確認する。そのため,計算量的には*O(n)*になる.また,扱えるファイルディスクリプタの数に上限があるため、現在はこのシステムコールを積極的に利用する理由は特にない。以下はselectを使ったsocket()、bind()、listen()後に準備ができているソケットを監視するプログラムだ。}}注目するのはこの部分。ここで監視するファイルディスクリプタの数だけループを回すことになる。}}pollpollはI/Oを多重化するためのシステムコールの1つで、selectで問題だったファイルディスクリプタの数が無制限になっている。select同様監視対象のファイルディスクリプタを1つずつ状態確認するため、その計算量は*O(n)*となる。そのため、ファイルディスクリプタの数が増えるとパフォーマンスが低下する。selectを利用するならpollを使う方が良い。以下はpollを使ったsocket(),bind(),listen()後に準備ができているソケットを監視するプログラムだ。}}selectを使ったプログラムと同様にループで監視するファイルディスクリプタの数だけループを回す必要があるためパフォーマンスを気にする場合は次のepollを利用したほうがいい。導入されたもので、2.6以降なら利用可能。epollはファイルディスクリプタの数に制限が無いのに加えて、ファイルディスクリプタの状態変化監視も改善されている。具体的には,ファイルディスクリプタの状態をカーネルで監視しており、変化したものを直接通知できるためselect、pollの時のようにループを使った監視をする必要がない。これにより、計算量は*O(1)*となり、よりパフォーマンスの高い多重化I/Oを実現できる。close(epollfd);}epollはselectやpollと異なりeventsに入っているデータは全て読み込み可能なファイルディスクリプタなので、O(1)の計算量で済む。{まとめI/O周りの様々な用語をまとめた。今回、自分の中ではノンブロッキングI/Oと非同期I/Oは異なるものだという結論をしたが、インターネット上の情報を参照する時はそれが何を表しているかは文脈で判断したい。今後は、Node.jsやNginxといった高度なI/O処理テクニックを利用しているサーバの実装について見ていこうと思う。今回の話は人によって意見が異なるので、参考文献は多めに載せておくこととする。書籍Linuxネットワークプログラミングバイブルは本書籍の多重化の章は説明もプログラムも豊富でC言語でI/O多重化の実装の流れを掴みたいときは参考になると思う。