緩衝與非緩衝I/O、直接與非直接I/O、阻塞與非阻塞I/O、同步與異步I/O

文件讀寫方式的各種差異,導致I/O的分類多種多樣。最常見的有緩衝與非緩衝I/O、直接與非直接I/O、阻塞與非阻塞I/O、同步與異步I/O。

根據是否利用標準庫緩存,可以把文件I/O分爲緩衝I/O與非緩衝I/O。

  • 緩衝I/O,是指利用標準庫緩存來加速文件的訪問,而標準庫內部再通過系統調度訪問文件。

  • 非緩衝I/O,是指直接通過系統調用來訪問文件,不再經過標準庫緩存。

 這裏所說的“緩衝”,是指標準庫內部實現的緩存。比方說,你可能見到過,很多程序遇到換行時才真正輸出,而換行前的內容,其實就是被標準庫暫時緩存了起來。

根據是否利用操作系統的頁緩存,可以把文件I/O分爲直接I/O與非直接I/O。

  • 直接I/O,是指跳過操作系統的頁緩存,直接跟文件系統交互來訪問文件。

  • 非直接I/O正好相反,文件讀寫時,先要經過系統的頁緩存,然後再由內核或額外的系統調用,真正寫入磁盤。

想要實現直接I/O,需要你在系統調用中,指定 O_DIRECT 標誌。如果沒有設置過,默認的是非直接I/O。

不過要注意,直接I/O、非直接I/O,本質上還是和文件系統交互。如果是在數據庫等場景中,你還會看到,跳過文件系統讀寫磁盤的情況,也就是我們通常所說的裸I/O。

根據應用程序是否阻塞自身運行,可以把文件I/O分爲阻塞I/O和非阻塞I/O:

  • 所謂阻塞I/O,是指應用程序執行I/O操作後,如果沒有獲得響應,就會阻塞當前線程,自然就不能執行其他任務。

  • 所謂非阻塞I/O,是指應用程序執行I/O操作後,不會阻塞當前的線程,可以繼續執行其他的任務,隨後再通過輪詢或者事件通知的形式,獲取調用的結果。

比方說,訪問管道或者網絡套接字時,設置 O_NONBLOCK 標誌,就表示用非阻塞方式訪問;而如果不做任何設置,默認的就是阻塞訪問。

根據是否等待響應結果,可以把文件I/O分爲同步和異步I/O:

  • 所謂同步I/O,是指應用程序執行I/O操作後,要一直等到整個I/O完成後,才能獲得I/O響應(需要主動讀寫數據,如read、write等操作)。

  • 所謂異步I/O,是指應用程序執行I/O操作後,不用等待完成和完成後的響應,而是繼續執行就可以。等到這次 I/O完成後,響應會用事件通知的方式,告訴應用程序(操作系統來完成數據的讀寫)。

舉個例子,在操作文件時,如果你設置了 O_SYNC 或者 O_DSYNC 標誌,就代表同步I/O。如果設置了O_DSYNC,就要等文件數據寫入磁盤後,才能返回;而O_SYNC,則是在O_DSYNC基礎上,要求文件元數據也要寫入磁盤後,才能返回。

再比如,在訪問管道或者網絡套接字時,設置了O_ASYNC選項後,相應的I/O就是異步I/O。這樣,內核會再通過SIGIO或者SIGPOLL,來通知進程文件是否可讀寫。

我們可能會問 阻塞、非阻塞 I/O 與同步、異步 I/O 的區別和聯繫

通過定義可以看出阻塞/非阻塞和同步/異步,其實就是兩個不同角度的 I/O 劃分方式。它們描述的對象也不同,阻塞/非阻塞針對的是 I/O 調用者(即應用程序),而同步/異步針對的是 I/O 執行者(即系統)。

知乎上大神陳碩老師的回答:

在處理 IO 的時候,阻塞和非阻塞都是同步 IO(我們使用的select/poll/epoll /read/write等函數都是同步IO)。只有使用了特殊的 API 纔是異步 IO。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章