Swift 與 Objective-C

同步 vs 非同步、阻塞 vs 非阻塞 — 完整整理 2×2 種組合

同步與非同步關注由誰處理工作完成,阻塞與非阻塞則關注是否立即交還控制權。由於兩個軸彼此獨立,因此 2×2 的四種組合都存在;本文搭配 Swift 範例說明原因。

閱讀 5 分鐘
同步 vs 非同步、阻塞 vs 非阻塞 — 完整整理 2×2 種組合 封面圖

同步和非同步大致懂了,但加入阻塞與非阻塞後就變得很複雜。

你可以在相關文章 程序 vs 執行緒:技術面試第一熱門問題完整整理(從記憶體結構理解) 中一起了解背景概念與延伸應用案例。Dispatch

你可能會想:「同步 = 阻塞、非同步 = 非阻塞,不是嗎?」但兩者其實是不同的軸。組合後會得到四種情況,而且實務上四種都存在。

每當談到網路程式碼、async/await,或 Node.js 這類事件迴圈時,就會遇到這些概念。只要一次把兩個軸釐清,就能長期活用。

本文會精確區分兩個軸,並搭配範例整理 2×2 種組合。

先從重點開始總結。

  1. 同步/非同步軸:由誰處理工作完成 — 呼叫端直接處理就是同步,收到通知就是非同步
  2. 阻塞/非阻塞軸:呼叫時是否立即交還控制權 — 不交還就是阻塞,立即交還就是非阻塞
  3. 兩個軸彼此獨立,因此 2×2 = 4 種組合全部存在
  4. 實務上最常遇到的是同步+阻塞、非同步+非阻塞兩種

軸 1:同步 vs 非同步 — 誰處理完成?

同步(synchronous)是由呼叫端直接處理工作是否完成的方式。送出請求後,流程會一直被該工作占住,直到取得結果。

A 結束後做 B,B 結束後做 C。順序受到保證。

非同步(asynchronous)是先送出請求、繼續處理其他工作,完成後再收到通知的方式。回呼、閉包,以及 async/await 的 continuation 都是這種「通知管道」(POSIX aio_read)。

用餐廳來比喻吧。同步就是點餐後站在櫃檯前,等餐點出來再拿走。

非同步則是拿著震動呼叫器,在座位上做其他事,呼叫器響了再去取餐。


軸 2:阻塞 vs 非阻塞 — 是否交還控制權

這次的觀點不同。判準是被呼叫的函式是否立即交還控制權。

阻塞(blocking)是呼叫後,呼叫端的執行緒會一直被占用到函式結束。在此期間執行緒什麼也做不了。

非阻塞(non-blocking)是呼叫後先立即返回。若結果尚未準備好,也會返回「還沒完成」這類狀態(POSIX read)。

如果同步/非同步是「完成管理方式」,阻塞/非阻塞就是「是否等待」。兩者是不同的軸。


完整檢視 2×2 種組合

由同步/非同步與阻塞/非阻塞兩個軸形成的 2×2 組合圖
兩個軸彼此獨立,因此四種組合全部存在
組合 行為 代表範例
同步 + 阻塞 等待並取得結果後繼續 一般函式呼叫、基本檔案 read
同步 + 非阻塞 立即返回,重複確認是否完成(輪詢) 非阻塞 Socket 在迴圈中持續確認
非同步 + 阻塞 等待通知,但執行緒被占住 設定非同步 API 後立即 wait 取得結果
非同步 + 非阻塞 先送出並做其他事,完成後收到通知 URLSession 回呼、async/await

同步+非阻塞可能很陌生,可以想成「沒有震動呼叫器,卻每分鐘到櫃檯問『好了嗎?』的客人」。

雖然掌握控制權,但完成由自己處理,所以是同步。

非同步+阻塞其實是吃虧的組合。做成非同步後卻立即等待結果,和同步+阻塞沒有差別,只是結構更複雜。

在非同步函式一開始就呼叫 wait 的程式碼,就是這種案例。


從 Swift 來看

GCD(Grand Central Dispatch)時代的 sync/async,其實比較接近是否阻塞的命名。

queue.sync 會把目前的執行緒綁住,直到閉包結束(阻塞)。queue.async 則送出工作後立即前往下一行(非阻塞)。

async/await 是讓非同步+非阻塞讀起來像同步程式碼的語法。

let data = try await fetchImage() // 這裡會「暫停」,但
// 執行緒不會被綁住,而是去處理其他工作

在 await 位置,函式會暫時停止,但執行緒會被釋放來處理其他工作。程式碼讀起來像同步流程一樣由上往下,但實際行為是非阻塞,這才是重點。

「不阻塞主執行緒,也不陷入回呼地獄,還能依序撰寫」就是這個語法存在的理由。

await 位置只有函式停止、執行緒持續前進的道路比喻插圖
在 await 位置函式會停止,但執行緒會被釋放去做其他工作

面試重點

第一步是各用一句話區分兩個軸的判準。

「阻塞/非阻塞是是否立即交還控制權的問題;同步/非同步則是呼叫端自行處理完成,或接收通知的問題。」

接著遇到「請舉出四種組合的例子」這個追問時,逐一回答表中的案例。尤其能說明同步+非阻塞(輪詢),就表示真正理解了兩個軸。


總結

  • 同步/非同步:呼叫端直接處理完成就是同步,收到通知就是非同步
  • 阻塞/非阻塞:呼叫時不交還控制權就是阻塞,立即交還就是非阻塞
  • 兩個軸彼此獨立,因此四種組合全部存在
  • 同步+非阻塞是輪詢,非同步+阻塞大多是吃虧的組合
  • GCD 的 sync/async 比較接近是否阻塞,而 async/await 則讓非同步+非阻塞讀起來像同步程式碼
  • 餐廳比喻:在櫃檯等待(同步+阻塞)、每分鐘詢問(同步+非阻塞)、震動呼叫器(非同步+非阻塞)

來源與確認依據

  • 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 · 依據:以佇列為基礎的同步・非同步工作提交