iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Software Development

用作業系統讀懂另一半的OS系列 第 9

【2025鐵人賽】用作業系統讀懂另一半的OS:Threads & Concurrency 02

  • 分享至 

  • xImage
  •  

上一篇我們大致有說Thread了,接下來我們進一步討論效能這方面的事情。
首先我們要先介紹一個定律:Amdahl’ s Law(安達爾定律)

Amdahl’ s Law(安達爾定律)

理論上來說,核心越多,速度是會越快,但但但,效能這件事,他還是會有一個極限存在。
那這邊就可以用Amdahl’ s Law來做表示:

https://ithelp.ithome.com.tw/upload/images/20250726/201777640PlYKwoenk.png

其中S是不能平行的比例(serial 部分),N是CPU 核心數。舉例而言:
假設電腦當中,75% 可平行(0.75),25% 必須串行執行(0.25)。
那如果以:
2 顆核心 → 最快提升 ≈ 1.6 倍
4 顆核心 → 最快提升 ≈ 2.28 倍
...
∞ 顆核心 → 最大速度 = 1 / 0.25 = 4 倍

也就是說,即使有 100 顆核心,若程式裡面有 25% 不能平行,最大速度也只能提升 4 倍。

多執行緒模型(Multithreading Models)

就像上一篇文所提到的,現在程序為了提升效率,常常會用「Thread」來分工處理任務。
但有個問題來了,我們之前有提到OS本身是Dual Mode,可以分為kernal mode跟user mode。那使用者程式的使用者執行緒(User Thread)怎麼跟作業系統的核心執行緒(Kernel Thread)搭配呢?

第一個,Many-to-One model

多個User Thread去對應一個Kernel Thread。
優點:建立快、切換便宜(因為都在使用者空間處理)
缺點:只要一個人卡住,大家都動不了,而且多核心也無法用上!

https://ithelp.ithome.com.tw/upload/images/20250726/20177764c0md6i1RNp.png

第二個,One-to-One model

每個User Thread都會去對應到一個Kernel Thread。
優點:真正支援平行執行(多核心發揮),一個阻塞不會拖累其他。
缺點:正也是因為每建立一個User Thread,都得分配一個kernal Thread,開太多會壓垮系統。

https://ithelp.ithome.com.tw/upload/images/20250726/20177764eAMHvMtWBV.png

Many-to-Many(多對多)

多個User Thread會去映射一組Kernel Thread(數量不一定相等)。
優點:可以建立很多user thread,核心只處理部分執行緒(核心與效能平衡)。且支援平行處理,不會因為一個 thread 阻塞整個 process。

https://ithelp.ithome.com.tw/upload/images/20250726/20177764IO1sgxAFyn.png

隱式多執行緒(Implicit Threading)

在傳統的Multithreading Programing中,開發者必須明確建立每個執行緒(thread creation)、指定工作分配(task assignment)、處理同步與互斥問題(如 mutex、semaphore)、這就像身兼老闆與搬運工,既要規劃又要親自操作,非常繁瑣且容易出錯。

因此,近代設計便提出隱式多執行緒(Implicit Threading)的概念。開發者只需要定義工作項目(tasks),開發者只需要專注於主要開發,細節交給系統或執行環境代勞。系統會自動判斷如何分配、何時執行。

而這樣的細節可能使用執行緒池、排程器或其他機制處理。這讓設計變得更像是「我提出工作需求,系統負責高效執行」,好比有個智慧工頭自動安排人力,開發者則可專注於邏輯設計與功能實現。四種常見的隱式多執行緒技術如下:

Thread Pool(執行緒池)

Thread Pool 是一種常見的「隱式多執行緒」機制,它的核心理念是:事先建立好一群執行緒(如10個工人),等有任務來時,就分派任務給空閒的執行緒處理,而不是每次都重新建立新的執行緒。這種方式就像是一家工廠,裡面早就雇好了幾位工人,工作來時馬上就有人手,不必臨時面試、訓練、報到。Thread Pool的運作流程如下:

  1. 初始化階段:系統建立一個執行緒池,裡面含有固定數量的工作執行緒(例如 10 個)。
  2. 提交任務:當開發者呼叫某個 API 或框架函式提交任務時,任務會進入「工作佇列」。
  3. 執行緒分派:執行緒池中的空閒執行緒會從佇列中取出任務執行。
  4. 重複使用:任務完成後,該執行緒會「回收」並重新等待下個任務。

Thread Pool的優點如下:
第一,資源重用:不需要頻繁建立與銷毀執行緒,節省系統資源與時間開銷(Thread Creation 很昂貴)。
第二,控制並發:可限制同時最多幾個任務執行(例如最多 10 個),避免 CPU/記憶體爆掉。
第三,降低延遲:任務一來馬上執行,不必等建立新 thread,對即時系統很重要。
第四,支援排程:執行緒池可結合 Timer 或 Scheduler,實作定時任務、延遲執行、週期任務等。

然而,Thread Pool也是有需要注意的地方:
第一,任務堵塞風險:若任務執行時間過長,執行緒都被佔住,會導致後續任務卡住(佇列塞滿)。
第二,錯誤處理:任務拋出例外可能導致 thread 掉線,需妥善處理(如 try-catch 包裹)。
第三,池大小設計:若 thread pool 太小 → 無法滿足任務量;太大 → 系統負擔過重,反而拖慢效能

Fork-Join 模型(分叉 - 合併)

Fork-Join 是一種經典的平行設計模型,特別適用於可切割成多個子任務的問題,例如:排序、矩陣運算、圖像處理等。它的核心精神是:把一個大任務切成多個小任務(Fork),讓它們同時執行,等都做完後,再把結果整合起來(Join)。

用形容的話,比較像是媽媽叫你把衣服分類、叫弟妹們幫忙洗、曬,最後再一起摺衣服。

Fork-Join的流程如下:

  1. Fork(分叉):主執行緒(Main Thread)將一個大任務拆分成多個小任務。這些小任務會以執行緒的方式平行展開執行。
  2. Execute(執行):每個執行緒處理自己負責的小任務。
  3. Join(合併):等所有子任務完成後,主執行緒會將它們的結果「合併」起來,完成最終工作。

Fork-Join的優點如下:

  • 適合大量計算工作:可分割的計算越多,越能發揮並行效率
  • 自動負載平衡(如 Java ForkJoinPool):系統可根據 CPU 核心動態調整任務分派
  • 可擴展性高:加 CPU 就能處理更多

然而,Thread Pool也是有需要注意的地方:

  • 任務不易切割時效能差:若某些子任務特別重,會拖累整體速度
  • join() 等待點若設計不當 → 變同步瓶頸
  • 遞迴太深會造成 stack overflow(可設計 threshold)

剩下兩種,一種是 OpenMP(跑在 C/C++/Fortran 上,老牌穩重型)
另一種是 GCD(Grand Central Dispatch,Apple 專用,走華麗精緻路線)
啊...不過,有點累,就先這樣摟(笑

https://ithelp.ithome.com.tw/upload/images/20250805/20177764mIKicp1rYz.jpg


上一篇
【2025鐵人賽】用作業系統讀懂另一半的OS:Threads & Concurrency 01
下一篇
【2025鐵人賽】用作業系統讀懂另一半的OS:CPU Scheduling 01
系列文
用作業系統讀懂另一半的OS30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言