Core / Process / Thread / Fiber / Coroutine Differences and Explanations

CPU Core / Process / Thread / Fiber / Coroutine 差異與解釋

前言

程式是可被執行的代碼或指令,而作業系統透過統整不同概念達成有效率的執行程式,理解以下概念可以幫助更好理解多工或並行程式的運作原理與運行效率最佳化:

  1. CPU Core(處理器核心)
  2. Process(進程 / 程序)
  3. Thread(線程 / 執行緒)
  4. Fibers(纖程)
  5. Coroutine (協程)

CPU Core(處理器核心)是什麼?

單顆 CPU 可以包含多個 Core,每個核心都能獨立執行運算指令,核心越多意味著電腦同時處理更多工作,單一程式也能透過 muti-core 來處理更多運算。

Physical Core 與 Logical Core

  • Physical Core:實際存在於 CPU 上的硬體可用於執行運算。
  • Logical Core:為了讓 CPU 在原本會「空閒等待」時把資源運用用更滿,透過讓 Physical Core 同時執行來自不同 thread 指令的技術。想像工廠等待 A 產線原物料送入時就可以先忙 B 產線的任務,達成併發(Concurrency)的目的。

Process(進程 / 程序)

當啟動程式作業系統會為其分配獨立的記憶體空間、狀態與系統資源。每一個 Process 是彼此隔離的互不干擾的,這也是為什麼單一軟體崩潰也不會導致其他程式崩潰。

Thread(線程 / 執行緒)

一個 Process 可以有一或多個 Thread,而所有 Thread 共用 Process 的記憶體。

Process (擁有獨立記憶資源)
├─ Thread 1
├─ Thread 2
└─ Thread 3

Thread 之間雖然可以共享記憶體資源,但也可能延伸額外 Race Condition 的問題與解套方案:

  1. Mutex(互斥鎖)保護某段程式碼一次只能被一個 Thread 執行。
  2. Semaphore(信號量)有數量限制的通行證,像停車場計數器。
  3. Atomic Operations(原子操作)保證「讀、修改、寫」一整步是不可中斷的。
  4. Message Passing 不共享記憶體,透過 Thread 間傳遞訊息。
go-channels.go
// “Do not communicate by sharing memory; share memory by communicating.”
ch := make(chan int)
go func() { ch <- 1 }()
value := <-ch
  1. Immutable Data(不變資料)不改動資料而是複製為新資料來操作
  2. ……

更輕量的執行序

雖然切換 Thread 的成本相較於 Process 已經低得多,但在某些「任務切換頻繁、但每個任務又相當輕量」的場景中,Thread 的開銷仍然顯得過高。 為了進一步降低成本,發展出「在應用層級模擬執行單位」的做法,也就是不依賴作業系統調度,而由程式自身控制的執行流程。常見的實作有 Coroutine 與 Fiber。

Coroutine (協程)

可以理解為「能夠暫停與恢復執行的函式」。

與一般函式不同,協程不一定要一次執行完畢,它可以在執行過程中「讓出控制權」,並在之後「從中斷的地方繼續執行」。這讓我們可以在單一 Thread 中,以非同步的方式協調多個任務的進行。

我基本想像它是 JavaScript 的 generator,而更常見的 async await 其實就是 generator + Promise 的語法糖,讓開發者能夠以同步的書寫風格撰寫非同步流程。

Fiber(纖程)

可以理解為「由作業系統支援的協程」。

它仍然需要開發者手動控制「切換時機」,也就是在程式內顯式地指定何時讓出控制權。由於這種切換不需要透過作業系統的排程,因此速度極快。

Fiber 的概念在不同語言與平台上的實作差異頗大。

總結

  • CPU Core:決定硬體可以同時做多少事情。
  • Process:程式運行時的容器,提供獨立記憶空間。
  • Thread:程式中真正執行工作的單位,共享 Process 資源。
  • Coroutine 與 Fibers:透過代碼層面實現更輕量的任務切換。

延伸閱讀