read系統呼叫,mmap系統呼叫

2021-09-01 18:05:52 字數 3620 閱讀 8017

***read系統呼叫,mmap系統呼叫

2012-07-23 09:54:28| 分類: linux | 標籤:linux 檔案系統 虛擬記憶體 儲存系統 |字型大小 訂閱

一般情況下,操作檔案既可以使用標準i/o,也可直接使用系統呼叫。兩者有何區別呢?

在輸入輸出中,直接使用底層的系統呼叫效率是非常低的,為什麼?

(1) 系統呼叫會影響系統效能。執行系統呼叫時,linux必須從使用者態**

切換到核心態,然後再返回使用者**。

(2) 硬體會對底層系統呼叫一次所能讀寫的資料塊做出一定的限制。

帶快取的檔案操作是標準c 庫的實現,第一次呼叫帶快取的檔案操作函式時標準庫會自動分配記憶體並且讀出一段固定大小的內容儲存在快取中。所以以後每次的讀寫操作並不是針對硬碟上的檔案直接進行的,而是針對記憶體中的快取的。何時從硬碟中讀取檔案或者向硬碟中寫入檔案有標準庫的機制控制。不帶快取的檔案操作通常都是系統提供的系統呼叫,更加低階,直接從硬碟中讀取和寫入檔案,由於io瓶頸的原因,速度並不如意,而且原子操作需要程式設計師自己保證,但使用得當的話效率並不差。另外標準庫中的帶快取檔案io 是呼叫系統提供的不帶快取io實現的。

「術語不帶緩衝指的是每個read和write都呼叫嗯核心中的乙個系統呼叫。所有的磁碟i/o都要經過核心的塊緩衝(也稱核心的緩衝區快取記憶體),唯一例外的是對原始磁碟裝置的i/o。既然read或write的資料都要被核心緩衝,那麼術語「不帶緩衝的i/o「指的是在使用者的程序中對這兩個函式不會自動緩衝,每次read或write就要進行一次系統呼叫。「--------摘自

#include

void main()

; int ret = 0;

do while(ret);

} read.c

[cpp] view plaincopy

#include

#include

void main()

; int ret = 0;

do while(ret);

} 將它們編譯後得到的可執行程式fread和read分別在同一臺pc(linux系統)上執行,得到的如果如下:

[c-sharp] view plaincopy

[xiangy@compiling-server test_read]$ time ./fread

real 0m0.603s

user 0m0.597s

sys 0m0.006s

[xiangy@compiling-server test_read]$ time ./read

real 0m15.240s

user 0m3.847s

sys 0m11.392s

[xiangy@compiling-server test_read]$ ll test.file

-rw-r--r-- 1 xiangy svx8004 23955531 sep 24 17:17 test.file

發現沒有?fread與read的效率差有數十倍之多!可見啊~ read乙個位元組這種寫法是相當不可取的!

但是,事情為什麼會是這樣的呢?讓我們用strace來看看:

[c-sharp] view plaincopy

[xiangy@compiling-server test_read]$ strace ./fread

execve("./fread", ["./fread"], [/* 34 vars */]) = 0

…… read(3, "bzh91ay&sy/20v/322/25/4/320/240/177/377/377/377/377/376"..., 4096) = 4096

…… [xiangy@compiling-server test_read]$ strace ./read

execve("./read", ["./read"], [/* 34 vars */]) = 0

…… read(3, "b", 1) = 1

…… 看到了吧~fread庫函式在內部做了快取,每次讀取4096個位元組;而read就老老實實乙個位元組乙個位元組地讀……

那麼再想想,我們讀的是什麼?是磁碟。難道上面提到的差異,就是因為這4096倍的讀磁碟次數差而引起的嗎?並不是這樣。

磁 盤是塊裝置,每次讀取的最小單位是塊。而當我們通過系統呼叫讀乙個位元組時,linux會怎麼做呢?它會是讀取乙個塊、然後返回乙個位元組、再把其餘位元組都丟 掉嗎?當然不會,這樣的作業系統也太拙劣了……換個角度想一想,如果真是每read乙個位元組就操作一次磁碟去讀乙個塊,那麼上面的test.file有 24m之大,近兩千四百萬次的磁碟讀操作也不大可能會在15秒鐘完成吧~

實際上linux的檔案系統層(fs層)不但不是這樣拙劣,反而很高明。不僅會將每次讀的一整塊資料快取下來,還有預讀機制(一次預讀多個塊,以減少磁碟尋道時間)。

那麼,fread與read執行的效率差來自於**呢?實際上就是來自於4096倍的系統呼叫次數差!fread庫函式中快取的作用並不是減少讀磁碟的次數,而是減少系統呼叫的次數。

由此可見,系統呼叫比起普通函式呼叫有很大的開銷,編寫**時應當注意儘量減少系統呼叫的使用。

為了進一步減少系統呼叫的次數,關於讀檔案的這個問題,我們還可以這樣做:

mmap.c

[cpp] view plaincopy

#include

#include

#include

#include

#include

#include

void main()

; int ret = 0;

fstat(fd, &statbuf);

start = mmap(null, statbuf.st_size, prot_read, map_private, fd, 0);

do while(ret < statbuf.st_size);

} 同樣是遍歷整個檔案,但是讀檔案的過程中不需要使用系統呼叫。(原理是:mmap的執行,僅僅是在核心中建立了檔案與虛擬記憶體空間的對應關係。使用者訪問這些虛擬記憶體空間時,頁面表裡面是沒有這些空間的表項的,於是產生缺頁異常。核心捕捉這些異常,逐漸將檔案讀入。)

將其編譯後得到的可執行程式mmap和之前的fread、read分別在同一臺pc上執行,得到的如果如下:

[c-sharp] view plaincopy

[xiangy@compiling-server test_read]$ time ./fread

real 0m0.901s

user 0m0.892s

sys 0m0.010s

[xiangy@compiling-server test_read]$ time ./mmap

real 0m0.112s

user 0m0.106s

sys 0m0.006s

[xiangy@compiling-server test_read]$ time ./read

real 0m15.549s

user 0m3.933s

sys 0m11.566s

[xiangy@compiling-server test_read]$ ll test.file

-rw-r--r-- 1 xiangy svx8004 23955531 sep 24 17:17 test.file

mmap方式與fread方式相比,效率還要高出幾倍。

read系統呼叫

read系統呼叫是glibc庫裡面的乙個函式,是對系統呼叫函式sys read 的封裝與實現。glic庫會將read函式在使用者態下進行解析,通過暫存器將引數儲存起來,並借助於系統呼叫名稱獲得系統呼叫號,該系統呼叫號又可以作為系統呼叫函式在sys call table中的索引獲取函式入口位址,該錶位...

mmap系統呼叫

mmap 系統呼叫 功能 void mmap void addr size t len int prot int flags int fd off t offset 記憶體對映函式 mmap,負責把檔案內容對映到 程序的虛擬記憶體空間 通過對這段記憶體的讀取 和修改,來實現對檔案的讀取和修改 而不需...

mmap系統呼叫

void mmap void addr size t len int prot int flags int fd off t offset 記憶體對映函式mmap,負責把檔案內容對映到程序的虛擬記憶體空間,通過對這段記憶體的讀取和修改,來實現對檔案的讀取和修改,而不需要再呼叫read,write等操...