同期と非同期はなんとなく分かりますが、ブロッキングとノンブロッキングまで出てくると混乱します。
関連記事プロセス vs スレッド、技術面接で最もよく聞かれる質問を完全整理(メモリ構造で理解)では、背景概念と応用例を続けて確認できます。Dispatch
「同期 = ブロッキング、非同期 = ノンブロッキングでは?」と思いがちですが、これは別の軸です。組み合わせると4つのケースになり、実際にすべて存在します。
ネットワークコードやasync/await、Node.jsのようなイベントループの話になると必ず登場する概念です。軸を一度正しく理解すれば、何度でも役立ちます。
この記事では2つの軸を正確に分け、2×2の組み合わせを例とともに整理します。
まず要点をまとめます。
- 同期・非同期の軸:完了を誰が管理するか — 呼び出し側が直接管理すれば同期、通知を受ければ非同期
- ブロッキング・ノンブロッキングの軸:呼び出し時に制御権をすぐ返すか — 返さなければブロッキング、すぐ返せばノンブロッキング
- 2つの軸は独立しているため、2×2 = 4つの組み合わせがすべて存在する
- 実務でよく使うのは同期+ブロッキングと非同期+ノンブロッキングです
軸1:同期 vs 非同期 — 完了を誰が管理するのか
同期(synchronous)は、処理が完了したかどうかを呼び出し側が直接管理する方式です。リクエストを送ると、結果が返るまで処理の流れはその処理に拘束されます。
Aが終わったらB、Bが終わったらC。順序が保証されます。
非同期(asynchronous)は、リクエストだけ投げて次の作業を進め、完了したら通知を受ける方式です。コールバック、クロージャ、async/awaitのcontinuationは、すべてこの「通知窓口」です(POSIX aio_read)。
レストランにたとえてみましょう。同期は注文後、カウンターの前で料理が出るまで待って受け取ることです。
非同期は呼び出しベルを受け取り、席で別のことをしながら、ベルが鳴ったら取りに行くことです。
軸2:ブロッキング vs ノンブロッキング — 制御権を返すのか
ここでは視点が異なります。呼び出された関数が制御権をすぐ返すかどうかが基準です。
ブロッキング(blocking)は、呼び出すと関数が終了するまで呼び出し元のスレッドが拘束されることです。その間、スレッドは何もできません。
ノンブロッキング(non-blocking)は、呼び出すといったん即座にリターンします。結果が準備できていなければ、「まだ準備できていません」という状態でも返します(POSIX read)。
同期・非同期が「完了の管理方式」なら、ブロッキング・ノンブロッキングは「待機するかどうか」です。軸が異なります。
2×2の組み合わせをすべて確認する
| 組み合わせ | 動作 | 代表例 |
|---|---|---|
| 同期 + ブロッキング | 待機して結果を受け取ってから進む | 一般的な関数呼び出し、基本的なファイルread |
| 同期 + ノンブロッキング | すぐリターンし、完了したか繰り返し確認する(ポーリング) | ノンブロッキングソケットをループで継続的に確認 |
| 非同期 + ブロッキング | 通知を待つ間、スレッドは拘束される | 非同期APIを設定して結果をすぐwaitする |
| 非同期 + ノンブロッキング | 投げて別の作業をし、完了したら通知を受ける | URLSessionコールバック、async/await |
同期+ノンブロッキングは、「呼び出しベルなしで、1分ごとにカウンターへ行き『できましたか?』と聞く客」です。
制御権は保持していますが、完了を自分で管理するため同期です。
非同期+ブロッキングは、実質的に損な組み合わせです。非同期にしておいて結果をすぐ待つと、同期+ブロッキングと変わらないのに構造だけ複雑になります。
非同期関数を呼び出してすぐwaitするコードがこの例です。
Swiftで見ると
GCD(Grand Central Dispatch)時代のsync/asyncは、実際にはブロッキングの有無に近い名前です。
queue.syncはクロージャが終わるまで現在のスレッドを拘束します(ブロッキング)。queue.asyncは投げてすぐ次の行へ進みます(ノンブロッキング)。
async/awaitは、非同期+ノンブロッキングを同期コードのように読めるようにする構文です。
let data = try await fetchImage() // ここで「中断」しますが
// スレッドは拘束されず、別の作業をしに行きます
awaitの位置で関数はいったん停止しますが、スレッドは解放されて別の処理を実行します。コードは同期のように上から下へ読める一方、実際の動作はノンブロッキングである点が重要です。
「メインスレッドをブロックせず、コールバック地獄にもならず、順番どおりに書ける」ことがこの構文の存在理由です。
面接のポイント
まず、2つの軸の基準をそれぞれ一文で区別しましょう。
「ブロッキング・ノンブロッキングは制御権をすぐ返すかの問題で、同期・非同期は呼び出し側が完了を管理するか通知を受けるかの問題です。」
次に「4つの組み合わせの例を挙げてください」という追加質問には、表の例を一つずつ答えます。特に同期+ノンブロッキング(ポーリング)を説明できれば、軸を正しく理解している証拠になります。
まとめ
- 同期・非同期:呼び出し側が完了を直接管理すれば同期、通知を受ければ非同期
- ブロッキング・ノンブロッキング:呼び出し時に制御権を返さなければブロッキング、すぐ返せばノンブロッキング
- 2つの軸は独立しているため、4つの組み合わせがすべて存在する
- 同期+ノンブロッキングはポーリング、非同期+ブロッキングはほとんどの場合で不利な組み合わせ
- GCDのsync/asyncはブロッキングの有無に近く、async/awaitは非同期+ノンブロッキングを同期コードのように読めるようにした構文です
- レストランのたとえ:カウンターで待つ(同期+ブロッキング)、1分ごとに尋ねる(同期+ノンブロッキング)、呼び出しベル(非同期+ノンブロッキング)
出典と確認基準
- POSIX read — The Open Group · 標準・仕様原文 · 確認 2026-08-17 · 根拠:ブロッキングI/OとO_NONBLOCKの動作
- POSIX aio_read — The Open Group · 標準・仕様原文 · 確認 2026-08-17 · 根拠:非同期I/Oリクエストと完了モデル
- Dispatch — Apple · 公式ドキュメント · 確認 2026-08-17 · 根拠:キューベースの同期・非同期タスク送信

