Home
探索 Uedu
學生控制台
註冊會員/登入
研究知情同意中心
教師控制台
課程設定
支援與訊息
Uptime 數據

UeduGPTs

--

Jupyters

4

UG26 CISOSE26
臺北 AQI 46 · 臺中 AQI 26 · 臺南 AQI 21 · 高雄 AQI 33

AI 回覆桌面通知

AI 助教回覆完成時顯示桌面通知

聊天訊息通知

同學在討論區發送訊息時通知

聲音通知

每當有新通知時播放提示音

儲存與輸入輸出

儲存與輸入輸出

從 HDD 的旋轉磁碟到 SSD 的電子閘,再到中斷與 DMA 如何把 CPU 從緩慢的 I/O 中解放出來

為什麼關機後檔案還在,遊戲卻要「讀取中」?

想像你正在玩一款大型遊戲。按下開機鍵的瞬間,硬碟裡的作業系統被搬進記憶體,遊戲存檔安然無恙地躺在那裡——即使昨晚你直接拔掉電源也一樣。可是當你走進新地圖,畫面卻卡在「Loading...」的進度條前,CPU 明明強得能每秒算上百億次,卻只能乾等資料從儲存裝置慢慢爬過來。

這兩個現象——「斷電後資料還在」與「讀取資料很慢」——背後是計算機系統最核心的一道鴻溝:記憶體階層(memory hierarchy)輸入輸出(I/O) 的世界。本文要談的,正是這個離 CPU 較遠、卻決定整台電腦使用體驗的領域:資料如何被儲存、如何在裝置與處理器之間流動,以及系統如何聰明地避免讓昂貴的 CPU 白白空等。

揮發與非揮發:資料為什麼「記得住」

要理解儲存,先要分清兩種記憶體性質。

揮發性記憶體(volatile memory) 一旦斷電,內容立刻消失。主記憶體 DRAM(動態隨機存取記憶體)就是典型——它靠電容儲存電荷,電荷會持續漏掉,必須不斷「更新(refresh)」才能維持。斷電就等於停止更新,資料瞬間蒸發。CPU 內的暫存器(register)與快取(cache)更是如此。

非揮發性記憶體(non-volatile memory) 則在斷電後仍保留資料。硬碟(HDD)、固態硬碟(SSD)、USB 隨身碟都屬此類。你的遊戲存檔、作業系統、照片之所以關機後還在,正因為它們住在非揮發性的儲存裝置裡。

這個分野解釋了電腦的基本工作流程:程式與資料平時「冷藏」在非揮發的儲存裝置,執行時才被搬進揮發但快速的主記憶體,CPU 再從記憶體(透過快取)取用。整個系統可以畫成一座金字塔:

電腦硬體與組織概念示意圖

越往上越快、越貴、容量越小(暫存器、快取、DRAM);越往下越慢、越便宜、容量越大(SSD、HDD、磁帶)。設計的藝術,就在於讓常用資料盡量待在上層。

HDD 與 SSD:機械臂與電子閘的對決

非揮發儲存的兩大主角,運作原理天差地別。

機械硬碟(HDD):旋轉的磁碟與飛行的磁頭

HDD 內部是一疊高速旋轉的磁碟片(platter),表面塗有磁性材料。資料以磁化方向(0 或 1)記錄在同心圓的磁軌(track) 上,每條磁軌再切成數個磁區(sector)。一支裝著讀寫頭的磁臂(actuator arm) 在碟片上方數奈米處「飛行」,靠移動到正確磁軌、等待目標磁區轉到磁頭下方來存取資料。

因此 HDD 的存取時間由三部分組成:

  • 尋道時間(seek time):磁臂移到目標磁軌的時間,數毫秒。
  • 旋轉延遲(rotational latency):等待磁區轉到磁頭下方,與轉速(如 7200 RPM)相關。
  • 傳輸時間(transfer time):實際讀寫資料的時間。

關鍵在於:因為牽涉機械移動,HDD 對「隨機存取」特別不友善。讀分散在各處的小檔案,磁臂得來回奔波;而連續讀大檔案則快得多。這就是為什麼磁碟「重組(defragmentation)」對 HDD 有意義。

固態硬碟(SSD):沒有任何活動零件

SSD 用 NAND 快閃記憶體(flash memory) 儲存資料,內部沒有任何機械結構。資料存在由浮閘電晶體(floating-gate transistor)組成的記憶胞中,靠困住電子的有無來表示 0 與 1。沒有磁臂、沒有旋轉,存取任何位置幾乎一樣快,所以 SSD 的隨機存取效能遠勝 HDD。

但 SSD 有其獨特性質:

  • 讀寫不對稱:可以對單一頁(page) 讀寫,但抹除(erase) 必須以更大的區塊(block) 為單位進行。要改寫一頁,往往得先搬走整塊資料、抹除、再寫回。
  • 寫入次數有限:每個記憶胞能承受的抹寫次數有上限,因此 SSD 控制器會做 磨損平均(wear leveling),把寫入分散到各處,避免某些胞提早報廢。

下表整理兩者差異:

特性 HDD(機械硬碟) SSD(固態硬碟)
儲存原理 磁化方向 浮閘電晶體電荷
活動零件 有(碟片、磁臂)
隨機存取 慢(受機械限制)
抗震動
單位容量成本 較高
典型延遲 毫秒級(ms) 微秒級(μs)
揮發性 非揮發 非揮發

兩者都是非揮發儲存,但 SSD 的速度讓它成為現代主流,HDD 則因為便宜大容量,仍活躍在資料倉儲與備份場景。

匯流排與週邊:資料的高速公路

裝置之間靠什麼連接?答案是匯流排(bus)——一組共享的傳輸線路,負責在 CPU、記憶體與週邊裝置間搬運資料、位址與控制訊號。

常見的匯流排與介面包括:

  • PCIe(PCI Express):連接顯示卡、NVMe SSD 等高速裝置的點對點通道。
  • SATA:傳統 HDD 與一般 SSD 的介面。
  • USB:通用的外接週邊匯流排(隨身碟、鍵盤、滑鼠)。
  • 記憶體匯流排:CPU 與 DRAM 之間的專屬通道。

週邊裝置(peripheral)透過裝置控制器(device controller) 接上匯流排。控制器內含暫存器與緩衝區,作業系統的裝置驅動程式(device driver) 透過讀寫這些暫存器來下達指令、查詢狀態。CPU 不直接和磁碟「對話」,而是透過控制器這個中介。

CPU 如何知道 I/O 做完了?輪詢 vs 中斷

這裡進入本文的核心問題。CPU 速度以奈秒計,而磁碟存取以毫秒計——兩者相差百萬倍。當 CPU 對磁碟發出「讀取」指令後,它要如何得知資料已經備妥?有兩種策略。

輪詢(polling):一直問「好了沒?」

最直接的辦法是讓 CPU 不斷讀取裝置控制器的狀態暫存器,反覆檢查「忙碌中」的旗標是否清除:

loop:
    讀取裝置狀態暫存器
    若 仍為「忙碌」 → 跳回 loop
    否則 → 讀取資料

這就是忙碌等待(busy-waiting)。問題顯而易見:CPU 把寶貴的運算週期全花在「問問題」上,明明可以去執行別的程式,卻被綁在這個迴圈裡空轉。對慢速裝置而言,這是巨大的浪費。

中斷(interrupt):「好了我再叫你」

更聰明的做法是中斷驅動 I/O(interrupt-driven I/O)。CPU 對裝置下達指令後,不再等待,而是繼續執行其他工作。當裝置完成任務時,主動透過一條中斷請求線(IRQ) 通知 CPU。CPU 收到中斷後,暫停手邊工作、保存現場、跳去執行對應的中斷服務常式(ISR, Interrupt Service Routine) 處理結果,處理完再回到原本的工作。

這就像你把衣服丟進洗衣機後不站在旁邊盯著,而是去做別的事,等洗衣機「嗶」一聲再回來收。CPU 因此能在等待 I/O 的漫長時間裡服務其他程式,大幅提升整體吞吐量。這正是多工作業系統能流暢運作的基礎。

動手看一個例子:對比兩種策略的 CPU 浪費

假設一次磁碟讀取需要 10 毫秒(ms),而 CPU 每奈秒(ns)可執行一道指令。

輪詢版本——CPU 在這 10 ms 內全程空轉:

def read_block_polling(controller):
    controller.write_command("READ")
    while controller.status() == "BUSY":   # 忙碌等待
        pass                                # CPU 在此空轉約 10 ms
    return controller.read_data()

10 ms = $10 \times 10^6$ ns,意味著 CPU 白白浪費了約一千萬道指令的運算能力。

中斷版本——CPU 發出指令後立刻離開:

def read_block_interrupt(controller):
    controller.write_command("READ")
    controller.enable_interrupt()
    scheduler.switch_to_other_task()        # CPU 去做別的事

# 裝置完成後觸發此常式
def disk_isr(controller):
    data = controller.read_data()
    scheduler.wake_up(waiting_task)         # 喚醒原本等待的程式

在這 10 ms 裡,CPU 可以執行其他程式約一千萬道指令,而不是空等。兩種方式的差距,就是現代電腦能同時開瀏覽器、播音樂、下載檔案而不卡頓的原因之一。

那大量資料搬移呢?DMA 登場

中斷解決了「等待」的浪費,但還有一個問題:搬資料這件事本身。

若每讀一個位元組都要 CPU 親自從控制器搬到記憶體,那麼讀一個幾 MB 的檔案,CPU 就得執行數百萬次「搬一格」的動作,依然被綁死。直接記憶體存取(DMA, Direct Memory Access) 正是為此而生。

DMA 是一個獨立的硬體控制器。CPU 只需告訴它三件事:從哪個裝置讀搬到記憶體哪個位址搬多少,接著 CPU 就完全放手。DMA 控制器自行接管匯流排,把整批資料直接在裝置與記憶體之間搬運,完全不經過 CPU。整批搬完後,DMA 才發出一次中斷通知 CPU「全部搞定」。

於是,原本可能需要數百萬次中斷與搬移的工作,被壓縮成「下指令 → DMA 自己搬 → 一次中斷收尾」。CPU 在這段期間幾乎完全自由,可以全速執行其他運算。中斷驅動 I/O 讓 CPU 不必空等,DMA 則更進一步讓 CPU 連搬運都不必親自動手——這兩項機制共同把昂貴的處理器從緩慢的 I/O 中徹底解放出來。

重點回顧

  • 揮發 vs 非揮發:DRAM、快取斷電即失(揮發);HDD、SSD 斷電仍存(非揮發)。記憶體階層讓資料在快而貴、慢而便宜的層級間流動。
  • HDD vs SSD:HDD 靠機械式磁碟與磁臂,隨機存取慢、有尋道與旋轉延遲;SSD 用 NAND 快閃,無活動零件、隨機存取快,但有抹寫單位不對稱與壽命限制。
  • 匯流排與週邊:PCIe、SATA、USB 等匯流排連接裝置;CPU 透過裝置控制器與驅動程式間接操控週邊。
  • 輪詢 vs 中斷:輪詢讓 CPU 忙碌等待、浪費運算;中斷讓裝置完成後主動通知,CPU 得以去做別的事。
  • DMA:把整批資料搬運交給專屬控制器,CPU 只下指令、收一次中斷,徹底從資料搬移中解放。

深入探討(研究所視角)

中斷與 DMA 的代價:cache 一致性與中斷風暴。 DMA 雖然解放了 CPU,卻引入新的一致性問題。當 DMA 直接把新資料寫入主記憶體,CPU 的快取(cache) 中可能仍保留該位址的舊副本,造成 cache 與記憶體不一致。現代系統靠 cache 一致性協定或在 DMA 完成後使快取失效(cache invalidation) 來解決;具備 I/O coherency 的架構則讓 DMA 引擎參與一致性協定。另一方面,在高速網路或高 IOPS 的 NVMe SSD 上,若每個封包或請求都觸發一次中斷,中斷負荷(interrupt overhead) 本身會壓垮 CPU——這稱為 interrupt storm。對策包括 中斷合併(interrupt coalescing),累積數個事件才發一次中斷;以及如 Linux NAPI 的混合策略:高負載時暫時關閉中斷、改用輪詢批次處理封包,低負載時再回到中斷模式,在延遲與吞吐量間取得平衡。

儲存堆疊與作業系統的連結。 從這裡可以延伸到多個研究所層級的主題。檔案系統如何把連續的邏輯區塊對應到實體磁區,直接影響 I/O 效能;針對 SSD 的 FTL(Flash Translation Layer)TRIM 指令,讓作業系統能告知 SSD 哪些區塊已不再使用,配合垃圾回收與磨損平均維持效能與壽命。I/O 排程演算法(如電梯演算法 SCAN、針對 SSD 的 noop/mq-deadline)試圖最佳化請求順序。再往上,虛擬記憶體的分頁(paging)機制把磁碟當成記憶體的延伸,缺頁中斷(page fault)正是一種由 MMU 觸發、依賴 DMA 把頁面從儲存裝置載入的 I/O 事件。

效能模型與 Amdahl 定律的延伸。 當 CPU 被 I/O 解放後,系統瓶頸往往轉移到儲存與匯流排頻寬。以 Little's Law $L = \lambda W$(系統中平均請求數等於到達率乘以平均停留時間)可分析 I/O 佇列行為;而從整體加速比的角度,若 I/O 佔總執行時間比例為 $f$,再快的 CPU 也受限於 Amdahl 定律:

$$S = \frac{1}{(1-f) + \frac{f}{s}}$$

當 $f$ 偏大,提升 CPU 速度($s \to \infty$)的效益會迅速飽和。這正說明了為何現代系統設計把大量心力投注在縮短 I/O 路徑——非揮發記憶體(NVM)、記憶體級儲存(如 NVDIMM)、以及讓裝置直接存取使用者空間的 kernel bypass(如 SPDK、io_uring)——目標都是把資料離 CPU 更近、把中斷與系統呼叫的開銷壓到最低。儲存與 I/O 看似是計算機系統最「邊陲」的一環,卻恰恰是決定整體效能上限的關鍵戰場。

AI 共讀助教正在陪你讀:儲存與輸入輸出
嗨!我是這篇文章的共讀助教,只根據〈儲存與輸入輸出〉的內容回答。可以問我「解釋某段」「舉個例子」「出題考我」,或反白文中段落後點下方「解釋選取段落」。