計算機內功心法 二 讀取檔案時,程式經歷了什麼?

2022-01-10 16:37:07 字數 3294 閱讀 4498

在回答這個問題之前,我們先來看下為什麼對於計算機來說i/o是極其重要的。

相信對於程式設計師來說i/o操作是最為熟悉不過的了:

想一想,如果沒有i/o計算機該是一種多麼枯燥的裝置,不能看電影、不能玩遊戲,也不能上網,這樣的計算機最多就是乙個大號的計算器。

既然i/o這麼重要,那麼到底什麼才是i/o呢?

i/o就是簡單的資料copy,僅此而已。

這一點很重要,為了加深大家的印象,來,everybody,follow me,那邊樹上的朋友,還有那邊牆上的朋友們,舉起你們的雙手,跟我唱,蒼茫的天涯是。。。sorry,i/o僅僅就是資料copy、i/o僅僅就是資料copy。

讓我們先把演唱會的事情放在一邊,既然是copy資料,又是從**copy到**呢?

如果資料是從外部裝置copy到記憶體中,這就是input。

如果資料是從記憶體copy到外部裝置,這就是output。

記憶體與外部裝置之間不嫌麻煩的來回copy資料就是input and output,簡稱i/o(input/output),僅此而已。

img現在我們知道了什麼是i/o,接下來就是重點部分了,大家注意,坐穩了。

我們知道現在的cpu其主頻都是數ghz起步,這是什麼意思呢?簡單說就是cpu執行機器指令的速度是納秒級別的,而通常的i/o比如磁碟操作,一次磁碟seek大概在毫秒級別,因此如果我們把cpu的速度比作戰鬥機的話,那麼i/o操作的速度就是肯德雞

img也就是說當我們的程式跑起來時(cpu執行機器指令),其速度是要遠遠快於i/o速度的,那麼接下來的問題就是二者速度相差這麼大,那麼我們該如何設計、該如何更加合理的高效利用系統資源呢?

既然有速度差異,而且程序在執行完i/o操作前不能繼續向前推進,那麼顯然只有乙個辦法,那就是等待,wait

同樣是等待,有聰明的等待,也有傻傻的等待,簡稱傻等,那麼是選擇聰明的等待呢還是選擇傻等呢?

很顯然,更好的方法就是先去幹其它事情,快遞來了再說。

因此這裡的關鍵點就是快遞沒到前手頭上的事情可以先暫停,切換到其它任務,等快遞過來了再切換回來

理解了這一點你就能明白執行i/o操作時底層都發生了什麼。

接下來讓我們以讀取磁碟檔案為例來講解這一過程。

現在記憶體中有兩個程序,程序a和程序b,當前程序a正在執行,如圖所示:

img程序a中有一段讀取檔案的**,不管在什麼語言中通常我們定義乙個用來裝資料的buff,然後呼叫read之類的函式,像這樣:

read(buff);

這就是一種典型的i/o操作,當cpu執行到這段**的時候會向磁碟傳送讀取請求,注意與cpu執行指令的速度相比,i/o操作操作是非常慢的,因此作業系統是不可能把寶貴的cpu計算資源浪費在無謂的等待上的,這時重點來了,注意接下來是重點哦。

由於外部裝置執行i/o操作是相當慢的,因此在i/o操作完成之前程序是無法繼續向前推進的,這就是所謂的阻塞,即通常所說的block。作業系統檢測到程序向i/o裝置發起請求後就暫停程序的執行,怎麼暫停執行呢?很簡單,只需要記錄下當前程序的執行狀態並把cpu的pc暫存器指向其它程序的指令就可以了。

程序有暫停就會有繼續執行,因此作業系統必須儲存被暫停的程序以備後續繼續執行,顯然我們可以用佇列來儲存被暫停執行的程序,如圖所示,程序a被暫停執行並被放到阻塞佇列中(注意,不同的作業系統會有不同的實現,可能每個i/o裝置都有乙個對應的阻塞佇列,但這種實現細節上的差異不影響我們的討論)。

img這時作業系統已經向磁碟傳送了i/o請求,因此磁碟driver開始將磁碟中的資料copy到程序a的buff中,雖然這時程序a已經被暫停執行了,但這並不妨礙磁碟向記憶體中copy資料。注意,現代磁碟向記憶體copy資料時無需借助cpu的幫助,這就是所謂的dma(direct memory access),這個過程如圖所示:

img讓磁碟先copy著資料,我們接著聊。

實際上作業系統中除了有阻塞佇列之外也有就緒佇列,所謂就緒佇列是指佇列裡的程序準備就緒可以被cpu執行了,你可能會問為什麼不直接執行非要有個就緒佇列呢?答案很簡單,那就是僧多粥少,在即使只有1個核的機器上也可以建立出成千上萬個程序,cpu不可能同時執行這麼多的程序,因此必然存在這樣的程序,即使其一切準備就緒也不能被分配到計算資源,這樣的程序就被放到了就緒佇列。

現在程序b就位於就緒佇列,萬事俱備只欠cpu,如圖所示:

img當程序a被暫停執行後cpu是不可以閒下來的,因為就緒佇列中還有嗷嗷待哺的程序b,這時作業系統開始在就緒佇列中找下乙個可以執行的程序,也就是這裡的程序b。

此時作業系統將程序b從就緒佇列中取出,找出程序b被暫停時執行到的機器指令的位置,然後將cpu的pc暫存器指向該位置,這樣程序b就開始執行啦,如圖所示:

img注意,注意,接下來的這段是重點中的重點。

最後需要注意的一點就是上面的講解中我們直接把磁碟資料copy到了程序空間中,但實際上一般情況下i/o資料是要首先copy到作業系統內部,然後作業系統再copy到程序空間中。因此我們可以看到這裡其實還有一層經過作業系統的copy,對於效能要求很高的場景其實也是可以繞過作業系統直接進行資料copy的,這也是本文描述的場景,這種繞過作業系統直接進行資料copy的技術被稱為zero-copy,也就零拷貝,高併發、高效能場景下常用的一種技術,原理上很簡單吧。

本文講解的是程式設計師常用的i/o,一般來說作為程式設計師我們無需關心,但是理解i/o背後的底層原理對於設計高效能、高併發系統是極為有益的,希望這篇能對大家加深對i/o的認識有所幫助。

計算機基礎(二) 程式執行

1 源程式如.c cpp 2 經過預處理器,得到被修改後的源程式.i 預處理器可以刪除注釋 包含其他檔案以及執行巨集 巨集macro是一段重複文字的簡短描寫 替代。3 經過編譯器,得到彙編文字.s 4 經過彙編器,得到可重定位目標程式,二進位制檔案.o 5 經過鏈結器,如printf.o加入,得到可...

天大計算機演算法程式題(二)

2015年 2014年 統計 include include using namespace std intmain cout case this list contains sheep n return0 測試資料 最長回文子串長度 給出乙個只由小寫英文本元 a,b,c y,z 組成的字串 s,求...

計算機基礎第二課時

檔案字尾名1.也稱副檔名 filename extension 2.是作業系統用來標誌檔案型別的一種機制 3.通常來說,乙個副檔名是跟在主檔名後面的,由乙個分隔符分隔。例如 前端開發知識要點.txt 的檔名中,前端開發知識要點是主檔名,txt為副檔名 絕對路徑與相對路徑絕對路徑 是從碟符開始的路徑,...