chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

讀取文件1個字節(jié)是否會導(dǎo)致磁盤IO?

開關(guān)電源芯片 ? 來源:開發(fā)內(nèi)功修煉 ? 作者:zhangyanfei01 ? 2021-07-09 09:42 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在日常開發(fā)中一些看似司空見慣的問題上,我覺得可能大多數(shù)人其實(shí)并沒有真正理解,或者理解的不夠透徹。不信我們來看以下一段簡單的讀取文件的代碼:

上圖中的代碼僅僅只是對某個文件讀取了一個字節(jié),基于這個代碼片段我們來思考:

1、讀取文件 1 個字節(jié)是否會導(dǎo)致磁盤 IO ?

2、如果發(fā)生了磁盤 IO,那發(fā)生的是多大的 IO 呢?

大家平時用的各種語言 C++、PHP、Java、Go 啥的封裝層次都比較高,把很多細(xì)節(jié)都給屏蔽的比較徹底。如果想把上面的問題搞清楚,需要剖開 Linux 的內(nèi)部來看 Linux 的 IO 棧。

一、大話 Linux IO 棧

廢話不多說,我畫了一個 Linux IO 棧的簡化版本。

通過 IO ??梢钥吹?,我們在應(yīng)用層簡單的一次 read 而已,內(nèi)核就需要 IO 引擎、VFS、PageCache、通用塊管理層、IO 調(diào)度層等許多個組件來進(jìn)行復(fù)雜配合才能完成。

那這些組件都是干啥的呢?我們挨個簡單過一遍。不想看這個的同學(xué)可以直接跳到第二節(jié)的讀文件讀過程。

1.1 IO 引擎

開發(fā)同學(xué)想要讀寫文件的話,在 lib 庫層有很多套函數(shù)可以選擇,比如 read & write,pread & pwrite。這事實(shí)上就是在選擇 Linux 提供的 IO 引擎。

我們開篇中代碼片用的 read 函數(shù)就屬于 sync 引擎。IO 引擎仍然處于上層,它需要內(nèi)核層的提供的系統(tǒng)調(diào)用、VFS、通用塊層等更底層組件的支持才能實(shí)現(xiàn)。

接著讓我們繼續(xù)深入到內(nèi)核,來介紹各個內(nèi)核組件。

1.2 系統(tǒng)調(diào)用

當(dāng)進(jìn)入到系統(tǒng)調(diào)用以后,也就進(jìn)入到了內(nèi)核層。

系統(tǒng)調(diào)用將內(nèi)核中其它組件的功能進(jìn)行封裝,然后通過接口的形式暴露給用戶進(jìn)程來訪問。

對于我們的讀取文件的需求,系統(tǒng)調(diào)用需要依賴 VFS 內(nèi)核組件。

1.3 VFS 虛擬文件系統(tǒng)

VFS 的思想就是在 Linux 上抽象一個通用的文件系統(tǒng)模型,對我們開發(fā)人員或者是用戶提供一組通用的接口,讓我們不用 care 具體文件系統(tǒng)的實(shí)現(xiàn)。VFS 提供的核心數(shù)據(jù)結(jié)構(gòu)有四個,它們定義在內(nèi)核源代碼的 include/linux/fs.h 和 include/linux/dcache.h 中。

superblock:Linux 用來標(biāo)注具體已安裝的文件系統(tǒng)的有關(guān)信息。

inode:Linux 中的每一個文件/目錄都有一個 inode,記錄其權(quán)限、修改時間等信息。

desty:目錄項(xiàng),是路徑中的一部分,所有的目錄項(xiàng)對象串起來就是一棵 Linux 下的目錄樹。

file:文件對象,用來和打開它的進(jìn)程進(jìn)行交互。

圍繞這這四個核心數(shù)據(jù)結(jié)構(gòu),VFS 也都定義了一系列的操作方法。比如,inode 的操作方法定義 inode_operations,在它的里面定義了我們非常熟悉的 mkdir 和 rename 等。對于 file 對象,定義了對應(yīng)的操作方法 file_operations ,如下:

// include/linux/fs.hstruct file {

。。。。。。

const struct file_operations *f_op

}

struct file_operations {

。。。。。。

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

。。。。。。

int (*mmap) (struct file *, struct vm_area_struct *);

int (*open) (struct inode *, struct file *);

int (*flush) (struct file *, fl_owner_t id);

}

注意 VFS 是抽象的,所以它的 file_operations 里定義的 read、write 都只是函數(shù)指針, 實(shí)際中需要具體的文件系統(tǒng)來實(shí)現(xiàn),例如 ext4 等等。

1.4 Page Cache

Page Cache。它的中文譯名叫頁高速緩存。它是 Linux 內(nèi)核使用的主要磁盤高速緩存,是一個純內(nèi)存的工作組件。Linux 內(nèi)核使用搜索樹來高效管理大量的頁面。

有了它,Linux 就可以把一些磁盤上的文件數(shù)據(jù)保留在內(nèi)存中,然后來給訪問相對比較慢的磁盤來進(jìn)行訪問加速。

當(dāng)用戶要訪問的文件的時候,如果要訪問的文件 block 正好存在于 Page Cache 內(nèi),那么 Page Cache 組件直接把數(shù)據(jù)從內(nèi)核態(tài)拷貝到用戶進(jìn)程的內(nèi)存中就可以了。如果不存在,那么會申請一個新頁,發(fā)出缺頁中斷,然后用磁盤讀取到的 block 內(nèi)容來填充它 ,下次直接使用。

看到這里,開篇的問題可能你就明白一半了,如果你要訪問的文件近期訪問過,那么 Linux 大概率就是從 Page cache 內(nèi)存中的拷貝給你就完事,并不會有實(shí)際的磁盤 IO 發(fā)生。

不過有一種情況下,Pagecache 不會生效, 那就是你設(shè)置了 DIRECT_IO 標(biāo)志。

1.5 文件系統(tǒng)

Linux 下支持的文件系統(tǒng)有很多,常用的有 ext2/3/4、XFS、ZFS 等。

要用哪種文件系統(tǒng)是在格式化的時候指定的。因?yàn)槊恳粋€分區(qū)都可以單獨(dú)進(jìn)行格式化,所以一臺 Linux 機(jī)器下可以同時使用多個不同的文件系統(tǒng)。

文件系統(tǒng)里提供對 VFS 的具體實(shí)現(xiàn)。除了數(shù)據(jù)結(jié)構(gòu),每個文件系統(tǒng)還會定義自己的實(shí)際操作函數(shù)。例如在 ext4 中定義的 ext4_file_operations。在其中包含的VFS中定義的 read 函數(shù)的具體實(shí)現(xiàn):do_sync_read 和 do_sync_write。

const struct file_operations ext4_file_operations = {

.llseek = ext4_llseek,

.read = do_sync_read,

.write = do_sync_write,

.aio_read = generic_file_aio_read,

.aio_write = ext4_file_write,

。。。。。。

}

和 VFS 不同的是,這里的函數(shù)就是實(shí)實(shí)在在的實(shí)現(xiàn)了。

1.6 通用塊層

文件系統(tǒng)還要依賴更下層的通用塊層。

對上層的文件系統(tǒng),通用塊層提供一個統(tǒng)一的接口讓供文件系統(tǒng)實(shí)現(xiàn)者使用,而不用關(guān)心不同設(shè)備驅(qū)動程序的差異,這樣實(shí)現(xiàn)出來的文件系統(tǒng)就能用于任何的塊設(shè)備。通過對設(shè)備進(jìn)行抽象后,不管是磁盤還是機(jī)械硬盤,對于文件系統(tǒng)都可以使用相同的接口對邏輯數(shù)據(jù)塊進(jìn)行讀寫操作。

對下層。I/O 請求添加到設(shè)備的 I/O 請求隊(duì)列。它定義了一個叫 bio 的數(shù)據(jù)結(jié)構(gòu)來表示一次 IO 操作請求(include/linux/bio.h)

1.7 IO 調(diào)度層

當(dāng)通用塊層把 IO 請求實(shí)際發(fā)出以后,并不一定會立即被執(zhí)行。因?yàn)檎{(diào)度層會從全局出發(fā),盡量讓整體磁盤 IO 性能最大化。

對于機(jī)械硬盤來說,調(diào)度層會盡量讓磁頭類似電梯那樣工作,先往一個方向走,到頭再回來,這樣整體效率會比較高一些。具體的算法有 deadline 和 cfg ,算法細(xì)節(jié)就不展開了,感興趣同學(xué)可以自行搜索。

對于固態(tài)硬盤來說,隨機(jī) IO 的問題已經(jīng)被很大程度地解決了,所以可以直接使用最簡單的 noop 調(diào)度器。

在你的機(jī)器上,通過dmesg | grep -i scheduler來查看你的 Linux 支持的調(diào)度算法。

通用塊層和 IO 調(diào)度層一起為上層文件系統(tǒng)屏蔽了底層各種不同的硬盤、U盤的設(shè)備差異。

二、讀文件過程

我們已經(jīng)把 Linux IO 棧里的各個內(nèi)核組件都簡單介紹一遍了。現(xiàn)在我們再從頭整體過一下讀取文件的過程

三、回顧開篇問題

回到開篇的第一個問題:讀取文件 1 個字節(jié)是否會導(dǎo)致磁盤 IO ?

從上述流程中可以看到,如果 Page Cache 命中的話,根本就沒有磁盤 IO 產(chǎn)生。

所以,大家不要覺得代碼里出現(xiàn)幾個讀寫文件的邏輯就覺得性能會慢的不行。操作系統(tǒng)已經(jīng)替你優(yōu)化了很多很多,內(nèi)存級別的訪問延遲大約是 ns 級別的,比機(jī)械磁盤 IO 快了好幾個數(shù)量級。如果你的內(nèi)存足夠大,或者你的文件被訪問的足夠頻繁,其實(shí)這時候的 read 操作極少有真正的磁盤 IO 發(fā)生。

假如 Page Cache 沒有命中,那么一定會有傳動到機(jī)械軸上進(jìn)行磁盤 IO 嗎?

其實(shí)也不一定,為什么,因?yàn)楝F(xiàn)在的磁盤本身就會帶一塊緩存。另外現(xiàn)在的服務(wù)器都會組建磁盤陣列,在磁盤陣列里的核心硬件Raid卡里也會集成RAM作為緩存。只有所有的緩存都不命中的時候,機(jī)械軸帶著磁頭才會真正工作。

再看開篇的第二個問題:如果發(fā)生了磁盤 IO,那發(fā)生的是多大的 IO 呢?

如果所有的 Cache 都沒有兜住 IO 讀請求,那么我們來看看實(shí)際 Linux 會讀取多大。真的按我們的需求來,只去讀一個字節(jié)嗎?

整個 IO 過程中涉及到了好幾個內(nèi)核組件。而每個組件之間都是采用不同長度的塊來管理磁盤數(shù)據(jù)的。

Page Cache 是以頁為單位的,Linux 頁大小一般是 4KB

文件系統(tǒng)是以塊(block)為單位來管理的。使用 dumpe2fs 可以查看,一般一個塊默認(rèn)是 4KB

通用塊層是以段為單位來處理磁盤 IO 請求的,一個段為一個頁或者是頁的一部分

IO 調(diào)度程序通過 DMA 方式傳輸 N 個扇區(qū)到內(nèi)存,扇區(qū)一般為 512 字節(jié)

硬盤也是采用“扇區(qū)”的管理和傳輸數(shù)據(jù)的

可以看到,雖然我們從用戶角度確實(shí)是只讀了 1 個字節(jié)(開篇的代碼中我們只給這次磁盤IO留了一個字節(jié)的緩存區(qū))。但是在整個內(nèi)核工作流中,最小的工作單位是磁盤的扇區(qū),為512字節(jié),比1個字節(jié)要大的多。

另外 block、page cache 等高層組件工作單位更大。其中 Page Cache 的大小是一個內(nèi)存頁 4KB。所以一般一次磁盤讀取是多個扇區(qū)(512字節(jié))一起進(jìn)行的。假設(shè)通用塊層 IO 的段就是一個內(nèi)存頁的話,一次磁盤 IO 就是 4 KB(8 個 512 字節(jié)的扇區(qū))一起進(jìn)行讀取。

另外我們沒有講到的是還有一套復(fù)雜的預(yù)讀取的策略。所以,在實(shí)踐中,可能比 8 更多的扇區(qū)來一起被傳輸?shù)絻?nèi)存中。

最后,啰嗦幾句

操作系統(tǒng)的本意是做到讓你簡單可依賴, 讓你盡量把它當(dāng)成一個黑盒。你想要一個字節(jié),它就給你一個字節(jié),但是自己默默干了許許多多的活兒。

我們雖然國內(nèi)絕大多數(shù)開發(fā)都不是搞底層的,但如果你十分關(guān)注你的應(yīng)用程序的性能,你應(yīng)該明白操作系統(tǒng)的什么時候悄悄提高了你的性能,是怎么來提高的。以便在將來某一個時候你的線上服務(wù)器扛不住快要掛掉的時候,你能迅速找出問題所在。

想繼續(xù)深入學(xué)習(xí)的同學(xué)可以參考《深入理解 Linux 內(nèi)核》之第十四章。

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11581

    瀏覽量

    217160

原文標(biāo)題:read 文件一個字節(jié)實(shí)際會發(fā)生多大的磁盤IO?

文章出處:【微信號:gh_3980db2283cd,微信公眾號:開關(guān)電源芯片】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    使用ftp下載固件,每次都會或多或少接收錯幾個字節(jié),怎么改善?

    使用EC600的4G模組,在進(jìn)行遠(yuǎn)程FTP下載固件升級時,每次都會或多或少接收錯幾個字節(jié),偶爾才出現(xiàn)一次接收完全正確的固件,所以導(dǎo)致重啟后qboot校驗(yàn)固件CRC不過,升級失敗現(xiàn)象,這種現(xiàn)象一般應(yīng)該如何查詢呢?準(zhǔn)備調(diào)整4G模組串口波特率進(jìn)行測試
    發(fā)表于 09-18 07:23

    下位機(jī)CY7C68013A發(fā)送數(shù)據(jù),上位機(jī)C#讀取數(shù)據(jù),510字節(jié)一幀,丟幀或者幀內(nèi)錯位是怎么回事?

    下位機(jī)CY7C68013A發(fā)送數(shù)據(jù),上位機(jī)C#在1while循環(huán)內(nèi)不斷地讀取數(shù)據(jù),510字節(jié)1幀,1
    發(fā)表于 05-30 07:43

    USB芯片CY7C68013A和FPGA進(jìn)行通信,從EP6讀取512字節(jié)是正常的,但是讀取2個字節(jié)失敗,為什么?

    大家好,USB芯片CY7C68013A和FPGA進(jìn)行通信,從EP6讀取512字節(jié)是正常的,但是讀取2個字節(jié)失?。╢pga端一直在發(fā))Bulk IN failed,謝謝
    發(fā)表于 05-30 07:12

    當(dāng)從接收DMA一次接收一個字節(jié)時,如何檢查是否已接收到任意長度的所有數(shù)據(jù)包呢?

    當(dāng)從接收 DMA 一次接收一個字節(jié)時,如何檢查是否已接收到任意長度的所有數(shù)據(jù)包?
    發(fā)表于 04-21 08:22

    S32k3是否可以在啟動和停止條件之間發(fā)送和接收多個字節(jié)?

    我正在使用 nxp s32k312-100 引腳 mcu。 我正在嘗試使用基于模型的設(shè)計(jì)工具箱使用 i2c。 在 simulink 中是否有一種方法我可以在啟動和停止條件之間發(fā)送和接收多個字節(jié)。 我正在嘗試連接 TMP75溫度傳感器。
    發(fā)表于 03-31 07:17

    是否可以使用DMA和LPSPI的3字節(jié)幀大?。?/a>

    case 語句要處理[i]byteseachwrite具有 1、2 和 4 字節(jié)的選項(xiàng)。沒有 3 個字節(jié)的情況。有可能嗎?這不可能嗎?這是否與 4
    發(fā)表于 03-17 06:47

    使用FPGA控制DLPC3438,采用IIC協(xié)議進(jìn)行讀寫操作,讀取的數(shù)據(jù)存在錯誤,無法正確從寄存器中讀取數(shù)據(jù)怎么解決?

    我使用FPGA控制DLPC3438,采用IIC協(xié)議進(jìn)行讀寫操作,主要存在如下問題: (1)當(dāng)寫入8個字節(jié)到0x2E地址時,通過Xilinx工具ChipScope抓取IIC信號,發(fā)現(xiàn)DLPC3438
    發(fā)表于 02-24 07:47

    vsan數(shù)據(jù)恢復(fù)—vsan緩存盤出現(xiàn)故障導(dǎo)致數(shù)據(jù)丟失的數(shù)據(jù)恢復(fù)案例

    VMware vsan架構(gòu)采用2+1模式。每臺設(shè)備只有一磁盤組(7+1),緩存盤的大小為240GB,容量盤的大小為1.2TB。 由于其中一臺主機(jī)(0號組設(shè)備)的緩存盤出現(xiàn)故障,
    的頭像 發(fā)表于 02-23 17:05 ?532次閱讀

    IO-Link收發(fā)器怎么數(shù)據(jù)讀取

    IO-Link(IEC61131-9)是一開放的標(biāo)準(zhǔn)串行通信協(xié)議,它允許從傳感器和設(shè)備中雙向交換數(shù)據(jù)。這些傳感器和設(shè)備需要支持IO-Link并連接到主機(jī)上。IO-Link收發(fā)器在這一
    的頭像 發(fā)表于 02-02 16:34 ?969次閱讀

    ADS1274用DRDY+TDM輸出模式下,讀到的第一個字節(jié)是無效的,為什么?

    ,如果連續(xù)采集發(fā)現(xiàn)一共有13有效讀數(shù)的字節(jié),而不是12。多次試驗(yàn)后,可以發(fā)現(xiàn)最后一個字節(jié)的最后一位有的讀到的1,后面全部是0,因而可以排
    發(fā)表于 01-08 08:17

    請問一下ADS1293讀取某一通道的高低2個字節(jié)的PACE數(shù)據(jù),如何判斷這是有效的PACE信號?

    請問一下ADS1293讀取某一通道的高低2個字節(jié)的PACE數(shù)據(jù),但是如何判斷這是有效的PACE信號? 在處理的時候,根據(jù)是否是有效的PACE數(shù)據(jù),才可以在ECG中設(shè)置起搏標(biāo)志。
    發(fā)表于 01-06 07:43

    用ads1158在讀取數(shù)據(jù)的時候,后面兩個字節(jié)的數(shù)據(jù)讀不到,為什么?

    我現(xiàn)在用的ads1158在讀取數(shù)據(jù)的時候,通道號是可以正常讀取的,但是后面兩個字節(jié)的數(shù)據(jù)讀不到,不管輸入信號怎么變化,讀到的兩個字節(jié)數(shù)據(jù)始終是一
    發(fā)表于 12-24 06:16

    什么是raid磁盤冗余陣列

    讀寫、如實(shí)現(xiàn)數(shù)據(jù)備份。 ? raid技術(shù)的作用 ? - 提高IO能力,磁盤并行讀寫 - 提高耐用性,磁盤冗余算法來實(shí)現(xiàn)- 具備冗余功能,節(jié)約成本 ? raid級別的作用、以及區(qū)別 ? - raid0 最小
    的頭像 發(fā)表于 12-16 16:41 ?1306次閱讀
    什么是raid<b class='flag-5'>磁盤</b>冗余陣列

    結(jié)構(gòu)體成員的順序影響結(jié)構(gòu)體的大小嗎

    { char a;????char?b;????int?c;}; 它在內(nèi)存中的排序是這樣的,第一 char 占 1 個字節(jié),緊接著第 2 char 也占
    的頭像 發(fā)表于 11-25 16:24 ?781次閱讀

    ADS1299-4配置完成后DOUT輸出還是216個字節(jié)嗎?

    4通道1299芯片 其配置完成后DOUT輸出還是216個字節(jié)嗎?還是說變成了120個字節(jié)?
    發(fā)表于 11-21 07:08