協同式多工解釋了 Coroutine(協程)為什麼能在排程上比執行緒(Thread)便宜,但還沒回答另一個問題:當一個 Coroutine 被暫停又恢復時,它的執行狀態到底存在哪裡?這就牽涉到 Coroutine 的另一個核心分類:有堆疊協程(Stackful Coroutine)與無堆疊協程(Stackless Coroutine)。

為什麼需要保存狀態#

不論是執行緒還是 Coroutine,「暫停 / 恢復」的本質都是:

  • 把當前的執行位置記下來(程式計數器、變數、呼叫關係)。
  • 等下次被排程時,從記下的位置繼續往下跑。

執行緒是怎麼做到的?每條執行緒都有自己的呼叫堆疊(Call Stack),切換時 OS 會儲存暫存器、堆疊指標、頁表狀態等資訊,下次再還原。這套機制完整但成本高。

Coroutine 也要解決同樣的問題,不過它有兩種設計選擇。

有堆疊協程(Stackful Coroutine)#

有堆疊協程給每個 Coroutine 配一個獨立的呼叫堆疊:

  • 暫停時把整個堆疊儲存起來,恢復時換回來。
  • 因為有自己的堆疊,所以可以在任意函式裡呼叫 yield() 或對應的暫停 API,不限制呼叫位置。
  • 缺點是每個 Coroutine 都要付出堆疊空間的成本,數量大時記憶體占用會明顯。

許多語言用的是這條路線,例如 Lua 的 coroutine、Go 的 goroutine(雖然 Go runtime 對堆疊做了動態調整)。

無堆疊協程(Stackless Coroutine)#

Kotlin 的 Coroutine 走的是另一條路:無堆疊協程。它不為每個 Coroutine 配一個獨立堆疊,而是把暫停所需的狀態存在物件裡。

關鍵字是 Continuation

  • 每個 suspend 函式(suspend function)背後都隱含一個 Continuation 實例。
  • Coroutine 暫停時,把當下的區域變數、執行位置等資訊塞進 Continuation
  • 恢復時呼叫 ContinuationresumeWith(...),從上次斷點繼續。

換句話說,Continuation 就是 Coroutine 內部的回呼(Callback),編譯器把 suspend 函式拆成一個狀態機,每個暫停點就是一個狀態。從外面看是線性的程式,從內部看是回呼鏈。

Kotlin Coroutine 使用 CPS(Continuation-Passing Style)轉換實作 suspend。雖然底層仍是回呼,但這層轉換由編譯器自動完成,使用者寫的還是線性風格的程式。

為什麼 Kotlin 選擇無堆疊#

選擇無堆疊有幾個直接好處:

  • 記憶體輕:不需要為每個 Coroutine 保留獨立堆疊,狀態只是個物件。
  • 可以與 JVM 緊密整合:Coroutine 跑在普通的 JVM 執行緒上,對偵錯與監控工具友善。
  • 對函式庫作者友善:不必額外維護堆疊管理。

代價也很明顯:

  • 不能在任意位置 suspend:suspend 函式只能從 suspend 函式或 Coroutine 範圍內呼叫,不能在普通函式中間隨手讓出。
  • 編譯後狀態機變多,呼叫鏈在堆疊追蹤上會比較不直覺。

CoroutineScope 與 Continuation 的關係#

第一個 Coroutine 程式裡用到的 coroutineScope { ... },作用之一就是提供承載 Continuation 的環境。當你在 scope 中呼叫 suspend 函式時:

  • 編譯器會把 Continuation 傳進去。
  • suspend 函式利用這個 Continuation 把工作完成後的「下一步」串起來。
  • 因為 Continuation 與 scope 綁在一起,scope 結束時內部的 Coroutine 也會收尾。

這也解釋了 suspend 函式為什麼一定要在 CoroutineScope 中執行:沒有 scope 就沒有對應的 Continuation,編譯器無從產生狀態機的串接。

小結#

  • Coroutine 的「暫停 / 恢復」要解決的是執行狀態保存的問題。
  • 有堆疊協程(Stackful Coroutine)給每個 Coroutine 一個獨立堆疊,靈活但成本高。
  • 無堆疊協程(Stackless Coroutine)把狀態放進 Continuation 物件,輕量但需要 suspend 配合。
  • Kotlin Coroutine 選擇了無堆疊路線,搭配編譯器的 CPS 轉換,讓我們可以用線性語法寫非同步程式。

原文出處#

  • 原書/iThome:https://ithelp.ithome.com.tw/articles/10261501
  • 原書/iThome:https://ithelp.ithome.com.tw/articles/10262296
  • 書本:Kotlin 小宇宙(iThome 鐵人賽系列書)