五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

這是一份很全很全的IO基礎(chǔ)知識與概念

2022-09-14 15:14 作者:Linux遠航者  | 我要投稿

什么是 IO

在計算機操作系統(tǒng)中,所謂的I/O就是?輸入(Input)和輸出(Output),也可以理解為讀(Read)和寫(Write),針對不同的對象,I/O模式可以劃分為磁盤IO模型和網(wǎng)絡(luò)IO模型。

IO操作會涉及到用戶空間內(nèi)核空間的轉(zhuǎn)換,先來理解以下規(guī)則:

  • 內(nèi)存空間分為用戶空間和內(nèi)核空間,也稱為用戶緩沖區(qū)和內(nèi)核緩沖區(qū);

  • 用戶的應(yīng)用程序不能直接操作內(nèi)核空間,需要將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間才能使用;

  • 無論是read操作,還是write操作,都只能在內(nèi)核空間里執(zhí)行;

  • 磁盤IO和網(wǎng)絡(luò)IO請求加載到內(nèi)存的數(shù)據(jù)都是先放在內(nèi)核空間的;

再來看看所謂的讀(Read)和寫(Write)操作:

  • 讀操作:操作系統(tǒng)檢查內(nèi)核緩沖區(qū)有沒有需要的數(shù)據(jù),如果內(nèi)核緩沖區(qū)已經(jīng)有需要的數(shù)據(jù)了,那么就直接把內(nèi)核空間的數(shù)據(jù)copy到用戶空間,供用戶的應(yīng)用程序使用。如果內(nèi)核緩沖區(qū)沒有需要的數(shù)據(jù),對于磁盤IO,直接從磁盤中讀取到內(nèi)核緩沖區(qū)(這個過程可以不需要cpu參與)。而對于網(wǎng)絡(luò)IO,應(yīng)用程序需要等待客戶端發(fā)送數(shù)據(jù),如果客戶端還沒有發(fā)送數(shù)據(jù),對應(yīng)的應(yīng)用程序?qū)蛔枞?,直到客戶端發(fā)送了數(shù)據(jù),該應(yīng)用程序才會被喚醒,從Socket協(xié)議找中讀取客戶端發(fā)送的數(shù)據(jù)到內(nèi)核空間,然后把內(nèi)核空間的數(shù)據(jù)copy到用戶空間,供應(yīng)用程序使用。

  • 寫操作:用戶的應(yīng)用程序?qū)?shù)據(jù)從用戶空間copy到內(nèi)核空間的緩沖區(qū)中(如果用戶空間沒有相應(yīng)的數(shù)據(jù),則需要從磁盤—>內(nèi)核緩沖區(qū)—>用戶緩沖區(qū)依次讀取),這時對用戶程序來說寫操作就已經(jīng)完成,至于什么時候再寫到磁盤或通過網(wǎng)絡(luò)發(fā)送出去,由操作系統(tǒng)決定。除非應(yīng)用程序顯示地調(diào)用了sync 命令,立即把數(shù)據(jù)寫入磁盤,或執(zhí)行flush()方法,通過網(wǎng)絡(luò)把數(shù)據(jù)發(fā)送出去。

  • 絕大多數(shù)磁盤IO和網(wǎng)絡(luò)IO的讀寫操作都是上述過程,除了后面要講到的零拷貝IO。

用戶空間&內(nèi)核空間

野生程序員對于這個概念可能比較陌生,這其實是 Linux 操作系統(tǒng)中的概念。虛擬內(nèi)存(操作系統(tǒng)中的概念,和物理內(nèi)存是對應(yīng)的)被操作系統(tǒng)劃分成兩塊:User Space(用戶空間 和 Kernel Space(內(nèi)核空間),本質(zhì)上電腦的物理內(nèi)存是不劃分這些的,只是操作系統(tǒng)開機啟動后在邏輯上虛擬劃分了地址和空間范圍。

操作系統(tǒng)會給每個進程分配一個獨立的、連續(xù)的虛擬內(nèi)存地址空間(物理上可能不連續(xù)),以32位操作系統(tǒng)為例,該大小一般是4G,即232 。其中將高地址值的內(nèi)存空間分配給系統(tǒng)內(nèi)核占用(網(wǎng)上查資料得知:Linux下占1G,Windows下占2G),其余的內(nèi)存地址空間分配給用戶進程使用。

因為我們不是要深入學習操作系統(tǒng),所以這里以32位系統(tǒng)舉例旨在幫助你理解原理。32 位的 LInux 操作系統(tǒng)下,0~3G為用戶空間,3~4G為內(nèi)核空間

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【865977150】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。?!前100名進群領(lǐng)取,額外贈送一份價值699的內(nèi)核資料包(含視頻教程、電子書、實戰(zhàn)項目及代碼)

那為什么要這樣劃分出空間范圍呢?

也很好理解,畢竟操作系統(tǒng)身份高貴,太重要了,不能和用戶應(yīng)用程序在一起玩耍,各自的數(shù)據(jù)都要分開存儲并且嚴格控制權(quán)限不能越界。這樣才能保證操作系統(tǒng)的穩(wěn)定運行,用戶應(yīng)用程序太不可控了,不同公司或者個人都可以開發(fā),碰到坑爹的誤操作或者惡意破壞系統(tǒng)數(shù)據(jù)直接宕機玩完了。隔離后應(yīng)用程序要掛你就掛,操作系統(tǒng)可以正常運行。

簡單說,內(nèi)核空間?是操作系統(tǒng)?內(nèi)核代碼運行的地方,用戶空間?是?用戶程序代碼運行的地方。當應(yīng)用進程執(zhí)行系統(tǒng)調(diào)用陷入內(nèi)核代碼中執(zhí)行時就處于內(nèi)核態(tài),當應(yīng)用進程在運行用戶代碼時就處于用戶態(tài)。

同時內(nèi)核空間可以執(zhí)行任意的命令,而用戶空間只能執(zhí)行簡單的運算,不能直接調(diào)用系統(tǒng)資源和數(shù)據(jù)。必須通過操作系統(tǒng)提供接口,向系統(tǒng)內(nèi)核發(fā)送指令。

一旦調(diào)用系統(tǒng)接口,應(yīng)用進程就從用戶空間切換到內(nèi)核空間了,因為開始運行內(nèi)核代碼了。

簡單看幾行代碼,分析下是應(yīng)用程序在用戶空間和內(nèi)核空間之間的切換過程:

str = "i am qige" // 用戶空間x = x + 2file.write(str) // 切換到內(nèi)核空間y = x + 4 // 切換回用戶空間

上面代碼中,第一行和第二行都是簡單的賦值運算,在用戶空間執(zhí)行。第三行需要寫入文件,就要切換到內(nèi)核空間,因為用戶不能直接寫文件,必須通過內(nèi)核安排。第四行又是賦值運算,就切換回用戶空間

用戶態(tài)切換到內(nèi)核態(tài)的3種方式:

  • 系統(tǒng)調(diào)用。也稱為 System Call,是說用戶態(tài)進程主動要求切換到內(nèi)核態(tài)的一種方式,用戶態(tài)進程使用操作系統(tǒng)提供的服務(wù)程序完成工作,比如上面示例代碼中的寫文件調(diào)用,還有像 fork() 函數(shù)實際上就是執(zhí)行了一個創(chuàng)建新進程的系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用的機制其核心還是使用了操作系統(tǒng)為用戶特別開放的一個中斷來實現(xiàn)。

  • 異常。當CPU在用戶空間執(zhí)行程序代碼時發(fā)生了不可預(yù)期的異常,這時會觸發(fā)由當前運行進程切換到處理此異常的內(nèi)核相關(guān)程序中,切換到內(nèi)核態(tài),比如缺頁異常。

  • 外圍設(shè)備的中斷。?當外圍設(shè)備完成用戶請求的某些操作后,會向CPU發(fā)送相應(yīng)的中斷信號,這時CPU會暫停執(zhí)行下一條即將執(zhí)行的指令轉(zhuǎn)而去執(zhí)行與中斷信號對應(yīng)的處理程序,如果當前正在運行用戶態(tài)下的程序指令,自然就發(fā)了由用戶態(tài)到內(nèi)核態(tài)的切換。比如硬盤數(shù)據(jù)讀寫完成,系統(tǒng)會切換到中斷處理程序中執(zhí)行后續(xù)操作等。

以上3種方式,除了系統(tǒng)調(diào)用是進程主動發(fā)起切換,異常和外圍設(shè)備中斷是被動切換的。

查看 CPU 時間在 User Space 與 Kernel Space 之間的分配情況,可以使用top命令。它的第三行輸出就是 CPU 時間分配統(tǒng)計。

我們來看看圖中圈出來的 CPU 使用率的三個指標:

其中,第一項 7.57% user 就是 CPU 消耗在 User Space 的時間百分比,第二項 7.0% sys是消耗在 Kernel Space 的時間百分比。第三項 85.4% idle 是 CPU 消耗在閑置進程的時間百分比,這個值越低,表示 CPU 越忙。

PIO&DMA

大家都知道一般我們的數(shù)據(jù)是存儲在磁盤上的,應(yīng)用程序想要讀寫這些數(shù)據(jù)肯定就需要加載到內(nèi)存中。接下來給大家介紹下?PIO?和?DMA?這兩種 IO 設(shè)備和內(nèi)存之間的數(shù)據(jù)傳輸方式。

PIO 工作原理

  1. 用戶進程通過read等系統(tǒng)調(diào)用接口向操作系統(tǒng)(即CPU)發(fā)出IO請求,請求讀取數(shù)據(jù)到自己的用戶內(nèi)存緩沖區(qū)中,然后該進程進入阻塞狀態(tài)。

  2. 操作系統(tǒng)收到用戶進程的請求后,進一步將IO請求發(fā)送給磁盤。

  3. 磁盤驅(qū)動器收到內(nèi)核的IO請求后,把數(shù)據(jù)讀取到自己的緩沖區(qū)中,此時不占用CPU。當磁盤的緩沖區(qū)被讀滿之后,向內(nèi)核發(fā)起中斷信號告知自己緩沖區(qū)已滿。

  4. 內(nèi)核收到磁盤發(fā)來的中斷信號,使用CPU將磁盤緩沖區(qū)中的數(shù)據(jù)copy到內(nèi)核緩沖區(qū)中。

  5. 如果內(nèi)核緩沖區(qū)的數(shù)據(jù)少于用戶申請讀的數(shù)據(jù),則重復(fù)步驟2、3、4,直到內(nèi)核緩沖區(qū)的數(shù)據(jù)符合用戶的要求為止。

  6. 內(nèi)核緩沖區(qū)的數(shù)據(jù)已經(jīng)符合用戶的要求,CPU停止向磁盤IO請求。

  7. CPU將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū),同時從系統(tǒng)調(diào)用中返回。

  8. 用戶進程讀取到數(shù)據(jù)后繼續(xù)執(zhí)行原來的任務(wù)。

PIO缺點:每次IO請求都需要CPU多次參與,效率很低。

DMA 工作原理

DMA(直接內(nèi)存訪問,Direct Memory Access)。

  1. 用戶進程通過read等系統(tǒng)調(diào)用接口向操作系統(tǒng)(即CPU)發(fā)出IO請求,請求讀取數(shù)據(jù)到自己的用戶內(nèi)存緩沖區(qū)中,然后該進程進入阻塞狀態(tài)。

  2. 操作系統(tǒng)收到用戶進程的請求后,進一步將IO請求發(fā)送給DMA,然后CPU就可以去干別的事了。

  3. DMA將IO請求轉(zhuǎn)發(fā)給磁盤。

  4. 磁盤驅(qū)動器收到內(nèi)核的IO請求后,把數(shù)據(jù)讀取到自己的緩沖區(qū)中,當磁盤的緩沖區(qū)被讀滿后,向DMA發(fā)起中斷信號告知自己緩沖區(qū)已滿。

  5. DMA收到磁盤驅(qū)動器的信號,將磁盤緩沖區(qū)中的數(shù)據(jù)copy到內(nèi)核緩沖區(qū)中,此時不占用CPU( PIO 這里是占用CPU的)。

  6. 如果內(nèi)核緩沖區(qū)的數(shù)據(jù)少于用戶申請讀的數(shù)據(jù),則重復(fù)步驟3、4、5,直到內(nèi)核緩沖區(qū)的數(shù)據(jù)符合用戶的要求為止。

  7. 內(nèi)核緩沖區(qū)的數(shù)據(jù)已經(jīng)符合用戶的要求,DMA停止向磁盤發(fā)IO請求。

  8. DMA發(fā)送中斷信號給CPU。

  9. CPU收到DMA的信號,知道數(shù)據(jù)已經(jīng)準備好,于是將數(shù)據(jù)從內(nèi)核空間copy到用戶空間,系統(tǒng)調(diào)用返回。

  10. 用戶進程讀取到數(shù)據(jù)后繼續(xù)執(zhí)行原來的任務(wù)。

跟PIO模式相比,DMA就是CPU的一個代理,它負責了一部分的拷貝工作,從而減輕了CPU的負擔。

需要注意的是,DMA承擔的工作是從磁盤的緩沖區(qū)到內(nèi)核緩沖區(qū)或網(wǎng)卡設(shè)備到內(nèi)核的 soket buffer的拷貝工作,以及內(nèi)核緩沖區(qū)到磁盤緩沖區(qū)或內(nèi)核的 soket buffer 到網(wǎng)卡設(shè)備的拷貝工作,而內(nèi)核緩沖區(qū)到用戶緩沖區(qū)之間的拷貝工作仍然由CPU負責。

可以肯定的是,PIO模式的計算機我們現(xiàn)在已經(jīng)很少見到了。

緩沖IO和直接IO

學習用戶空間和內(nèi)核空間的時候我們也說了,用戶空間是不能直接訪問內(nèi)核空間的數(shù)據(jù)的,如果需要訪問怎么辦?很簡單,就需要將數(shù)據(jù)從內(nèi)核空間拷貝的用戶空間。

  • 緩沖 IO:其實就是磁盤中的數(shù)據(jù)通過 DMA 先拷貝到內(nèi)核空間,然后再從內(nèi)核空間拷貝到用戶空間。

  • 直接 IO:磁盤中的數(shù)據(jù)直接通過 DMA 拷貝到用戶空間。

緩沖 IO

緩沖 IO 也被成為標準 IO,大多數(shù)的文件系統(tǒng)系統(tǒng)默認都是以緩沖 IO 的方式來工作的。在Linux的緩沖I/O機制中,數(shù)據(jù)先從磁盤復(fù)制到內(nèi)核空間的緩沖區(qū),然后從內(nèi)核空間緩沖區(qū)復(fù)制到應(yīng)用程序的地址空間。

接下來我們看看緩沖 IO 下讀寫操作是如何進行?

  • 讀操作:

操作系統(tǒng)檢查內(nèi)核的緩沖區(qū)有沒有需要的數(shù)據(jù),如果已經(jīng)緩沖了,那么就直接從緩沖中返回;否則從磁盤中讀取到內(nèi)核緩沖中,然后再復(fù)制到用戶空間緩沖中。

  • 寫操作:

將數(shù)據(jù)從用戶空間復(fù)制到內(nèi)核空間的緩沖中。這時對用戶程序來說寫操作就已經(jīng)完成,至于什么時候再寫到磁盤中由操作系統(tǒng)決定,除非顯示地調(diào)用了sync同步命令。

緩沖I/O的優(yōu)點:

  1. 在一定程度上分離了內(nèi)核空間和用戶空間,保護系統(tǒng)本身的運行安全;

  2. 因為內(nèi)核中有緩沖,可以減少讀盤的次數(shù),從而提高性能。

緩沖I/O的缺點:

在緩沖 I/O 機制中,DMA 方式可以將數(shù)據(jù)直接從磁盤讀到內(nèi)核空間頁緩沖中,或者將數(shù)據(jù)從內(nèi)核空間頁緩沖直接寫回到磁盤上,而不能直接在用戶地址空間和磁盤之間進行數(shù)據(jù)傳輸,這樣數(shù)據(jù)在傳輸過程中需要在應(yīng)用程序地址空間(用戶空間)和內(nèi)核緩沖(內(nèi)核空間)之間進行多次數(shù)據(jù)拷貝操作,這些數(shù)據(jù)拷貝操作所帶來的CPU以及內(nèi)存開銷是非常大的。

直接IO

顧名思義,直接IO就是應(yīng)用程序直接訪問磁盤數(shù)據(jù),而不經(jīng)過內(nèi)核緩沖區(qū),也就是繞過內(nèi)核緩沖區(qū),自己管理I/O緩沖區(qū),這樣做的目的是減少一次從內(nèi)核緩沖區(qū)到用戶程序緩沖的數(shù)據(jù)復(fù)制。

引入內(nèi)核緩沖區(qū)這個主要是為了提升從磁盤讀寫數(shù)據(jù)文件的性能,這也是很多系統(tǒng)優(yōu)化中常見的手段,多一層緩存可以有效減少很多磁盤 IO 操作;而當用戶程序需要向磁盤文件中寫入數(shù)據(jù)時,實際上只需要寫入到內(nèi)核緩沖區(qū)便可以返回了,而真正的落盤是有一定的延遲策略的,但這無疑提升了應(yīng)用程序?qū)懭胛募捻憫?yīng)速度。

在數(shù)據(jù)庫管理系統(tǒng)這類應(yīng)用中,它們更傾向于選擇自己實現(xiàn)的緩存機制,因為數(shù)據(jù)庫管理系統(tǒng)往往比操作系統(tǒng)更了解數(shù)據(jù)庫中存放的數(shù)據(jù),數(shù)據(jù)庫管理系統(tǒng)可以提供一種更加有效的緩存機制來提高數(shù)據(jù)庫中數(shù)據(jù)的存取性能。

直接I/O的優(yōu)點:

應(yīng)用程序直接訪問磁盤數(shù)據(jù),不經(jīng)過操作系統(tǒng)內(nèi)核數(shù)據(jù)緩沖區(qū),這樣做的最直觀目的是減少一次從內(nèi)核緩沖區(qū)到用戶程序緩沖的數(shù)據(jù)復(fù)制。這種方式通常用在數(shù)據(jù)庫、消息中間件中,由應(yīng)用程序來實現(xiàn)數(shù)據(jù)的緩存管理。

直接I/O的缺點:

如果訪問的數(shù)據(jù)不在應(yīng)用程序緩沖中,那么每次數(shù)據(jù)都會直接從磁盤進行加載,這種直接加載會非常緩慢。通常 直接I/O 跟 異步I/O 結(jié)合使用會得到較好的性能。(異步IO:當訪問數(shù)據(jù)的線程發(fā)出請求之后,線程會接著去處理其他事,而不是阻塞等待)

IO 訪問方式

我們常說的 IO 操作,不僅僅是磁盤 IO,還有常見的網(wǎng)絡(luò)數(shù)據(jù)傳輸即網(wǎng)絡(luò) IO。

磁盤 IO

讀操作:

當應(yīng)用程序調(diào)用read()方法時,操作系統(tǒng)檢查內(nèi)核高速緩沖區(qū)中是否存在需要的數(shù)據(jù),如果存在,那么就直接把內(nèi)核空間的數(shù)據(jù)copy到用戶空間,供用戶的應(yīng)用程序使用。如果內(nèi)核緩沖區(qū)沒有需要的數(shù)據(jù),通過通過DMA方式從磁盤中讀取數(shù)據(jù)到內(nèi)核緩沖區(qū),然后由CPU控制,把內(nèi)核空間的數(shù)據(jù)copy到用戶空間。

這個過程會涉及到兩次緩沖區(qū)copy,第一次是從磁盤到內(nèi)核緩沖區(qū),第二次是從內(nèi)核緩沖區(qū)到用戶緩沖區(qū),第一次是DMA的copy,第二次是CPU的copy。

寫操作:

當應(yīng)用程序調(diào)用write()方法時,應(yīng)用程序?qū)?shù)據(jù)從用戶空間copy到內(nèi)核空間的緩沖區(qū)中(如果用戶空間沒有相應(yīng)的數(shù)據(jù),則需要從磁盤—>內(nèi)核緩沖區(qū)—>用戶緩沖區(qū)),這時對用戶程序來說寫操作就已經(jīng)完成,至于什么時候把數(shù)據(jù)再寫到磁盤(從內(nèi)核緩沖區(qū)到磁盤的寫操作也由DMA控制,不需要cpu參與),由操作系統(tǒng)決定。除非應(yīng)用程序顯示地調(diào)用了sync命令,立即把數(shù)據(jù)寫入磁盤。

如果應(yīng)用程序沒準備好寫的數(shù)據(jù),則必須先從磁盤讀取數(shù)據(jù)才能執(zhí)行寫操作,這時會涉及到四次緩沖區(qū)的copy,第一次是從磁盤的緩沖區(qū)到內(nèi)核緩沖區(qū),第二次是從內(nèi)核緩沖區(qū)到用戶緩沖區(qū),第三次是從用戶緩沖區(qū)到內(nèi)核緩沖區(qū),第四次是從內(nèi)核緩沖區(qū)寫回到磁盤。前兩次是為了讀,后兩次是為了寫。這其中有兩次?CPU?拷貝,兩次DMA拷貝。

磁盤IO的延時:

為了讀或?qū)?,磁頭必須能移動到所指定的磁道上,并等待所指定的扇區(qū)的開始位置旋轉(zhuǎn)到磁頭下,然后再開始讀或?qū)憯?shù)據(jù)。磁盤IO的延時分成以下三部分:

  • 尋道時間:把磁頭移動到指定磁道上所經(jīng)歷的時間;

  • 旋轉(zhuǎn)延遲時間?:指定扇區(qū)移動到磁頭下面所經(jīng)歷的時間;

  • 傳輸時間?:數(shù)據(jù)的傳輸時間(數(shù)據(jù)讀出或?qū)懭氲臅r間);

網(wǎng)絡(luò) IO

讀操作:

網(wǎng)絡(luò) IO 既可以從物理磁盤中讀數(shù)據(jù),也可以從Socket中讀數(shù)據(jù)(從網(wǎng)卡中獲?。.攺奈锢泶疟P中讀數(shù)據(jù)的時候,其流程和磁盤IO的讀操作一樣。當從Socket中讀數(shù)據(jù),應(yīng)用程序需要等待客戶端發(fā)送數(shù)據(jù),如果客戶端還沒有發(fā)送數(shù)據(jù),對應(yīng)的應(yīng)用程序?qū)蛔枞钡娇蛻舳税l(fā)送了數(shù)據(jù),該應(yīng)用程序才會被喚醒,從Socket協(xié)議棧(網(wǎng)卡)中讀取客戶端發(fā)送的數(shù)據(jù)到內(nèi)核空間(這個過程也由DMA控制),然后把內(nèi)核空間的數(shù)據(jù) copy 到用戶空間,供應(yīng)用程序使用。

寫操作:

為了簡化描述,我們假設(shè)網(wǎng)絡(luò)IO的數(shù)據(jù)從磁盤中獲取,讀寫操作的流程如下:

  • 當應(yīng)用程序調(diào)用read()方法時,通過DMA方式將數(shù)據(jù)從磁盤拷貝到內(nèi)核緩沖區(qū);

  • 由cpu控制,將內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到用戶空間的緩沖區(qū)中,供應(yīng)用程序使用;

  • 當應(yīng)用程序調(diào)用 write() 方法時,CPU 會把用戶緩沖區(qū)中的數(shù)據(jù) copy 到內(nèi)核緩沖區(qū)的 Socket Buffer 中;

  • 最后通過DMA方式將內(nèi)核空間中的Socket Buffer拷貝到Socket協(xié)議棧(即網(wǎng)卡設(shè)備)中傳輸;

網(wǎng)絡(luò)IO?的寫操作也有四次緩沖區(qū)的copy,第一次是從磁盤緩沖區(qū)到內(nèi)核緩沖區(qū)(由DMA控制),第二次是內(nèi)核緩沖區(qū)到用戶緩沖區(qū)(CPU控制),第三次是用戶緩沖區(qū)到內(nèi)核緩沖區(qū)的 Socket Buffer(由CPU控制),第四次是從內(nèi)核緩沖區(qū)的 Socket Buffer 到網(wǎng)卡設(shè)備(由DMA控制)。四次緩沖區(qū)的copy工作兩次由CPU控制,兩次由DMA控制。

網(wǎng)絡(luò)IO的延時:

網(wǎng)絡(luò)IO主要延時是由:服務(wù)器響應(yīng)延時+帶寬限制+網(wǎng)絡(luò)延時+跳轉(zhuǎn)路由延時+本地接收延時?決定。一般為幾十到幾千毫秒,受環(huán)境影響較大。所以,一般來說,網(wǎng)絡(luò)IO延時要大于磁盤IO延時(不過同數(shù)據(jù)中心的交互除外,會比磁盤 IO 更快)。

零拷貝 IO

在上述IO中,一次讀寫操作要經(jīng)過四次緩沖區(qū)的拷貝,并經(jīng)歷了四次內(nèi)核態(tài)和用戶態(tài)的切換。?零拷貝(zero copy)IO?技術(shù)減少不必要的內(nèi)核緩沖區(qū)跟用戶緩沖區(qū)之間的拷貝,從而減少CPU的開銷和狀態(tài)切換帶來的開銷,達到性能的提升。

我們還是對比上面不使用零拷貝時的網(wǎng)絡(luò) IO 傳輸過程來對比分析下:

和上圖普通的網(wǎng)絡(luò) IO 傳輸過程對比,零拷貝的傳輸過程:硬盤 -> kernel buffer (快速拷貝到kernel socket buffer) -> Socket協(xié)議棧(網(wǎng)卡設(shè)備中)。

  • 當應(yīng)用程序調(diào)用read()方法時,通過DMA方式將數(shù)據(jù)從磁盤拷貝到內(nèi)核緩沖區(qū);

  • 由CPU控制,將內(nèi)核緩沖區(qū)的數(shù)據(jù)直接拷貝到另外一個與 Socket 相關(guān)的內(nèi)核緩沖區(qū),即kernel socket buffer;

  • 然后由 DMA 把數(shù)據(jù)從 kernel socket buffer 直接拷貝給 Socket 協(xié)議棧(網(wǎng)卡設(shè)備中);

這里,只經(jīng)歷了三次緩沖區(qū)的拷貝,第一次是從磁盤緩沖區(qū)到內(nèi)核緩沖區(qū),第二次是從內(nèi)核緩沖區(qū)到 kernel socket buffer,第三次是從 kernel socket buffer 到Socket 協(xié)議棧(網(wǎng)卡設(shè)備中)。只發(fā)生兩次內(nèi)核態(tài)和用戶態(tài)的切換,第一次是當應(yīng)用程序調(diào)用read方法時,用戶態(tài)切換到內(nèi)核態(tài)執(zhí)行read系統(tǒng)調(diào)用,第二次是將數(shù)據(jù)從網(wǎng)絡(luò)中發(fā)送出去后系統(tǒng)調(diào)用返回,從內(nèi)核態(tài)切換到用戶態(tài)。

零拷貝(zero copy)的應(yīng)用:

  • Linux 下提供了zero copy的接口:sendfile和splice,用戶可通過這兩個接口實現(xiàn)零拷貝傳輸;

  • Nginx 可以通過sendfile配置開啟零拷貝;

  • 在 Linux 系統(tǒng)中,Java NIO中 FileChannel.transferTo 的實現(xiàn)依賴于 sendfile()調(diào)用;

  • Apache 使用了 sendfile64() 來傳送文件,sendfile64() 是 sendfile() 的擴展實現(xiàn);

  • Kafka也用到了零拷貝的功能;

注意:零拷貝要求輸入的fd必須是文件句柄,不能是socket,輸出的fd必須是socket,也就是說,數(shù)據(jù)的來源必須是從本地的磁盤,而不能是從網(wǎng)絡(luò)中,如果數(shù)據(jù)來源于socket,就不能使用零拷貝功能了。我們看一下sendfile接口就知道了:

#include <sys/sendfile.h>ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)

  • out_fd:待寫入文件描述符;

  • in_fd:待讀出文件描述符;

  • offset:從讀入文件流的哪個位置開始讀,如果為空,則默認從起始位置開始;

  • count:指定在文件描述符in_fd 和out_fd之間傳輸?shù)淖止?jié)數(shù);

  • 返回值:成功時,返回出傳輸?shù)淖止?jié)數(shù),失敗返回-1;

in_fd 必須指向真實的文件,不能是socket和管道;而out_fd則必須是一個socket。由此可見,sendfile?幾乎是專門為在網(wǎng)絡(luò)上傳輸文件而設(shè)計的。

在Linxu系統(tǒng)中,一切皆文件,因此socket也是一個文件,也有文件句柄(或文件描述符)。

同步&異步、阻塞&非阻塞

這兩組概念,我接觸編程以來,經(jīng)過聽到別人說服務(wù)端是?同步非阻塞模型?或者?異步阻塞的 IO 模型,也前后了解過幾次,但是理解都不夠透徹,特別是這個非阻塞和異步、同步和阻塞的概念很容易懵逼,每個人的說法都不一樣,最近我耐心看了幾篇文章,這次我感覺我是頓悟了,這里分享下我的理解:

同步和異步是針對應(yīng)用程序向內(nèi)核發(fā)起任務(wù)后的狀態(tài)而言的:如果發(fā)起調(diào)用后,在沒有得到結(jié)果之前,當前調(diào)用就不返回,不能接著做后面的事情,一直等待就是同步。異步就是發(fā)出調(diào)用后,雖然不能立即得到結(jié)果,但是可以繼續(xù)執(zhí)行后面的事情,等調(diào)用結(jié)果出來時,會通過狀態(tài)、通知和回調(diào)來通知調(diào)用者。

舉個例子加深下理解:

  1. 在互聯(lián)網(wǎng)普及之前,我們?nèi)メt(yī)院看病都是排隊的模式,想看病就得排隊等,直到輪到你,在此之前你必須一直排隊等待,這個就是同步;

  2. 現(xiàn)在互聯(lián)網(wǎng)普及了,都是直接大屏叫號,我們預(yù)約登記后,就可以去休息廳坐著,打游戲啥的都可以干,到自己看病的時候會有通知的,這就是異步;

阻塞blocking、非阻塞non-blocking,則聚焦的是CPU在等待結(jié)果的過程中的狀態(tài)

阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當前線程會被掛起,只有在得到結(jié)果之后才會返回。你可能會把阻塞調(diào)用和同步調(diào)用等同起來,實際上它們是不同的,同步只是說必須等到出結(jié)果才可以返回,但是等的過程中線程可以是激活的,阻塞是說線程被掛起了。

非阻塞和阻塞的概念相對應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會阻塞當前線程,而會立刻返回。

比如前面的例子,排隊的過程中什么也不能做就是阻塞,CPU 執(zhí)行權(quán)是交出去的;一邊排隊,一邊看手機就是非阻塞,CPU 執(zhí)行權(quán)還在自己手里,但是沒看完病之前依舊是在排隊死等,所以還是同步的。

總結(jié)

通過今天的學習,我們掌握了什么是 IO、常見的 IO 操作類型以及對應(yīng)操作的原理,還有非常重要但是卻很容易搞混的同步&異步、阻塞&非阻塞之間的區(qū)別,講解的應(yīng)該還是比較清楚的。

本文內(nèi)容還是比較簡單的,是一些基礎(chǔ)知識,但是如果想深入學習網(wǎng)絡(luò)編程這些基礎(chǔ)是繞不開的,了解了操作系統(tǒng)對于 IO 操作的優(yōu)化,才能搞明白各種高性能網(wǎng)絡(luò)服務(wù)器的原理。



這是一份很全很全的IO基礎(chǔ)知識與概念的評論 (共 條)

分享到微博請遵守國家法律
彩票| 南木林县| 武功县| 石屏县| 依兰县| 石狮市| 栾川县| 富源县| 晋城| 明水县| 凤台县| 丰城市| 平潭县| 绍兴市| 辽阳县| 滁州市| 北宁市| 南安市| 弥渡县| 武川县| 江源县| 厦门市| 贵定县| 拉萨市| 怀仁县| 牡丹江市| 永昌县| 镇巴县| 昌宁县| 绿春县| 和硕县| 托克逊县| 门头沟区| 承德县| 通州区| 乃东县| 怀化市| 上犹县| 清镇市| 莱阳市| 临潭县|