轉自:https://blog.csdn.net/DLUTBruceZhang/article/details/9050467
https://www.cnblogs.com/yc3110/p/10440613.html
1.用戶與操作系統關系
在用戶空間中的進程要通過系統調用才能訪問系統資源。系統資源包括:
上面所說的這些系統資源,在用戶進程中是無法被直接訪問的,只能通過操作系統來訪問,所以也把操作系統提供的這些功能成為:“系統調用”。
2.用戶進程緩沖區
首先,用戶進程通過系統調用訪問系統資源的時候,需要切換到內核態,而這對應一些特殊的堆棧和內存環境,必須在系統調用前建立好。而在系統調用結束后,cpu會從核心模式切回到用戶模式,而堆棧又必須恢復成用戶進程的上下文。而這種切換就會有大量的耗時。
一些程序在讀取文件時,會先申請一塊內存數組,稱為buffer,然后每次調用read,讀取設定字節長度的數據,寫入buffer。(用較小的次數填滿buffer)。之后的程序都是從buffer中獲取數據,當buffer使用完后,在進行下一次調用,填充buffer。【緩沖區就可以理解為內存數組,在當前進程中開辟一段虛擬內存空間,並且映射到物理內存中,實際上存儲在物理內存中】
用戶緩沖區的目的是為了減少系統調用次數,從而降低操作系統在用戶態與核心態切換所耗費的時間。除了在進程中設計緩沖區,內核也有自己的緩沖區。
3.內核緩沖區
- 當一個用戶進程要從磁盤讀取數據時,內核一般不直接讀磁盤,而是將內核緩沖區中的數據復制到進程緩沖區中。【同步IO非阻塞的話,此時recvfrom只阻塞於數據從內核復制到用戶緩沖區這個過程】
- 但若是內核緩沖區中沒有數據,內核會把對數據塊的請求,加入到請求隊列,然后把進程掛起【這里說的應該是同步阻塞IO】,為其它進程提供服務。【同步IO非阻塞的話recvfrom獲取的狀態是無數據准備好,需要通過輪詢來判斷是否准備好,但是這個准備好只是存在於了內核緩沖區中,還沒有復制到用戶緩沖區中】
- 等到數據已經讀取到內核緩沖區時,把內核緩沖區中的數據讀取到用戶進程中,才會通知進程,當然不同的io模型,在調度和使用內核緩沖區的方式上有所不同。
read是把數據從內核緩沖區復制到進程緩沖區。write是把進程緩沖區復制到內核緩沖區。當然,write並不一定導致內核的寫動作(不等價於寫入磁盤),比如os可能會把內核緩沖區的數據積累到一定量后,再一次寫入。這也就是為什么斷電有時會導致數據丟失。所以說內核緩沖區,是為了在OS級別,提高磁盤IO效率,優化磁盤寫操作。
【個人認為,read和write都是系統調用函數,因為要訪問內核緩沖區或者寫入內核緩沖區,需要進入到內核態。但是因為有buffer的存在,如果這里有數據,就從這里讀,而不產生系統調用,節約時間。】
對比阻塞和非阻塞:
- 在阻塞io中,直到數據從內核緩沖區拷貝到用戶緩沖區才通知用戶進程調用完成並喚醒;
- 而非阻塞,在輪訓得知數據准備好后,數據還是在內核緩沖區中,等你去讀取,這也就是說數據准備好,並不代表已經讀好可以使用。當然也不代表一定能讀。【只是來到內核緩沖區了,還沒有拷貝到用戶緩沖區】
應用內核緩沖區的主要思想就是一次讀入大量的數據放在緩沖區,需要的時候從緩沖區取得數據:
- 提高了磁盤的I/O效率;
- 優化了磁盤的寫操作;
- 需要及時的將緩沖數據寫到磁盤。
4.為什么有需要將數據來回從內核到用戶緩沖區替換呢?
用戶進程是運行在用戶空間的,不能直接操作內核緩沖區的數據。 用戶進程進行系統調用的時候,會由用戶態切換到內核態,待內核處理完之后再返回用戶態。
- 應用緩沖技術能很明顯的提高系統效率。內核與外圍設備的數據交換,內核與用戶空間的數據交換都是比較費時的,使用緩沖區就是為了優化這些費時的操作。比如read本來從內核讀取數據時是比較費時的,所以一次取出一塊,以避免多次陷入內核。【這里說明了本人之前的理解是正確的。】