そもそもI/Oとは

Input/Outputの略で「入出力」を表す。

ファイルへの書き込みや読み込み、クライアント(webブラウザなど)とサーバーがやりとりを行うためのソケットへの入出力などを含む。

sequenceDiagram
    participant User
    participant File
		participant Client
		participant Server
    User->>File: ファイルへ書き込み
    File->>User: ファイルから読み込み
		Client->>Server: サーバーへ書き込み(リクエスト送信)
		Server->>Client: クライアントへ書き込み(レスポンス送信)

ブロッキングI/O

ブロッキングI/OではI/O処理時に対象のファイルディスクリプタが準備完了になっていない場合、ブロック状態、つまりプロセスはシステムコールの返答待ちに状態になり待機する。

その間プログラムの処理が進むことはない。

以下は、ブロッキングなread処理を行う時の状態遷移である。

sequenceDiagram
	participant A as Application
  participant K as Kernel
	A->>K: read()呼び出し
	activate A
	Note right of K: 読み込み開始
	Note left of A: 待機(ブロッキング)
	Note right of K: 読み込み完了
	K->>A: 読み込んだ結果をAppに移動
	deactivate A
// ブロッキングなファイルディスクリプタを読み込む

read(block_fd, buf, count) // readが終了してから、下の処理に進む
.
.

ノンブロッキングI/O

ノンブロッキングI/OではI/O対象のファイルディスクリプタの準備が完了していないことをアプリケーション側に伝えるために即座にエラーが返る。一般にはO_NONBLOCKフラグを利用してノンブロッキングモードにする。

エラーはアプリケーション側でハンドリングして、リトライするタイミングを定義する必要がある。

C10k問題の対策としてノンブロッキングI/Oとイベントループモデルを採用することで、シングルプロセス・シングルスレッドで複数の接続を処理する方法がある。

メリット


ノンブロッキング時はプロセスはブロック状態にはならず、CPUを他の処理に回すことができるため、I**/O待ち時間を有効活用**できる。

デメリット


ファイルディスクリプタの準備が完了するまで、毎回システムコールをチェックする(カーネルへのコンテキストスイッチが走る)必要があるので無駄が大きい