標籤:傳輸 sso 網路 http 需要 olap ibm 非阻塞io 環境
1 緩衝 I/O (Buffered I/O)介紹
對於傳統的作業系統來說,普通的 I/O 操作一般會被核心緩衝,這種 I/O 被稱作緩衝 I/O。緩衝 I/O 又被稱作標準 I/O,大多數檔案系統的預設 I/O 操作都是緩衝 I/O。在 Linux 的緩衝 I/O 機制中,作業系統會將 I/O 的資料緩衝在檔案系統的頁緩衝( page cache )中,也就是說,資料會先被拷貝到作業系統核心的緩衝區中,然後才會從作業系統核心的緩衝區拷貝到應用程式的地址空間。
(1) 對於讀操作來說,當應用程式嘗試讀取某塊資料的時候,如果這塊資料已經存放在了頁緩衝中,那麼這塊資料就可以立即返回給應用程式,而不需要經過實際的物理讀盤操作。當然,如果資料在應用程式讀取之前並未被存放在頁緩衝中,那麼就需要先將資料從磁碟讀到頁緩衝中去。一個典型的讀取磁碟中資料的流程圖如下所示:
(2) 對於寫操作來說,應用程式也會將資料先寫到頁緩衝中去,資料是否被立即寫到磁碟上去取決於應用程式所採用的寫操作機制:如果使用者採用的是同步寫機制( synchronous writes ), 那麼資料會立即被寫回到磁碟上,應用程式會一直等到資料被寫完為止;如果使用者採用的是延遲寫機制( deferred writes ),那麼應用程式就完全不需要等到資料全部被寫回到磁碟,資料只要被寫到頁緩衝中去就可以了。在延遲寫機制的情況下,作業系統會定期地將放在頁緩衝中的資料刷到磁碟上。與非同步寫機制( asynchronous writes )不同的是,延遲寫機制在資料完全寫到磁碟上的時候不會通知應用程式,而非同步寫機制在資料完全寫到磁碟上的時候是會返回給應用程式的。所以延遲寫機制本身是存在資料丟失的風險的,而非同步寫機制則不會有這方面的擔心。
緩衝 I/O 優點:
- 緩衝 I/O 使用了作業系統核心緩衝區,在一定程度上分離了應用程式空間和實際的物理裝置。緩衝 I/O 可以減少讀盤的次數,從而提高效能。
緩衝I/O缺點:
- 在緩衝 I/O 機制中,DMA 方式可以將資料直接從磁碟讀到頁緩衝中,或者將資料從頁緩衝直接寫回到磁碟上,而不能直接在應用程式地址空間和磁碟之間進行資料轉送,這樣的話,資料在傳輸過程中需要在應用程式地址空間和頁緩衝之間進行多次資料拷貝操作,這些資料拷貝操作所帶來的 CPU 以及記憶體開銷是非常大的。對於某些特殊的應用程式來說,避開作業系統核心緩衝區而直接在應用程式地址空間和磁碟之間傳輸資料會比使用作業系統核心緩衝區擷取更好的效能。
2 Linux環境下的network I/O
網路IO的本質就是socket的讀取,socket在linux系統被抽象為流,IO可以理解為對流的操作。文章開始的時候也提到了,對於一次IO訪問(以read為例),資料會先被拷貝到作業系統核心的緩衝區,然後才會從作業系統核心的緩衝區拷貝到應用程式的地址空間中。
所以說,當一個read操作發生時,它會經曆兩個階段:
第一個階段:等待資料準備。
第二個階段:將資料從核心拷貝到進程中
對於socket流而言:
第一步:通常涉及等待網路上的資料分組到達,然後複製到核心的某個緩衝區。
第二步:把資料從核心緩衝區複製到應用進程緩衝區。
Linux環境下的五種IO Modle: blocking IO, nonblocking IO, IO multiplexing, signal driven IO, asynchronous IO. 其中前四種比較常見。
(1) blocking IO
在阻塞IO模型中,從調用系統函數擷取資料開始到得到資料,當前的進程或者線程始終是處於阻塞狀態的,也就是什麼都不幹,直到等完資料準備好和將資料搬遷到使用者空間為止:
1) 使用者首先發出系統調用函數希望擷取資料;
2) 系統調用會進入核心檢查是否有資料準備完畢,如果沒有就一直等待;
3) 當資料準備完畢的時候會將資料拷貝到使用者空間;
4) 拷貝完畢返回一個擷取資料成功的傳回值來告訴使用者可以進行資料的處理了;在此期間,使用者進程或者線程一直是處於阻塞狀態的,無論是等待資料還是進行資料的拷貝;
(2) nonblocking IO
和阻塞式的IO模型不同,當發出了系統調用的時候,如果這時候資料還沒有準備好,進程或線程並不會進入阻塞模式一直等待,而是會反覆輪詢“資料好沒…資料好沒…資料好沒…”,這是比較耗CPU資源的,而當資料準備好之後會和阻塞IO模型一樣進行資料的拷貝:
1) 首先使用者發出系統調用,去向核心申請擷取想要的資料;
2) 核心檢查探索資料還沒準備好,就會返回一個錯誤值;
3) 使用者接收到錯誤值並不甘心,就會反覆反覆詢問核心是否有資料準備好;
4) 核心一直檢查直到有資料準備完畢,進行資料的搬遷,這時使用者會進入阻塞等待狀態等待資料拷貝完畢;
5) 資料提取到使用者空間之後會返回一個成功狀態通知使用者資料完畢,這時使用者就可以進行資料的處理了;
(3) IO multiplexing
既然是複用,說明一次性可以管理或處理多個IO,主要是靠select函數或者poll(epoll)函數來完成;這些函數同樣會阻塞進程,但是和阻塞式IO不同的是IO複用模型可以一次性阻塞多個IO操作。同時,kernel會“監視”所有select負責的socket,當任何一個socket中的資料準備好了,select就會返回。這個時候使用者進程再調用read操作,將資料從kernel拷貝到使用者進程。
1) 使用者首先調用select或者poll函數對多個IO介面操作進行檢測,同時會使進程或者線程阻塞;
2) 當有至少一個IO介面響應的時候,系統就會通知核心調用相應的函數來擷取資料;
3) 這時核心將資料拷貝遷移至核心空間,進程或者線程仍然處於阻塞狀態;
4) 資料就緒,返回一個成功值告訴使用者可以處理資料了;
(4) signal driven IO
使用者首先註冊一個處理IO訊號的訊號處理函數,當資料還沒準備好的時候進程或者線程並不阻塞,當資料準備好的時候使用者進程或者線程會收到一個訊號SIGIO,這時候就會調用訊號處理函數,在訊號處理函數中調用IO函數操作資料,完成之後通知使用者:
1) 使用者程式中事先註冊好一個對於SIGIO的訊號處理函數;
2) 當資料準備完畢的時候會向使用者進程或者線程發送一個SIGIO訊號,這時訊號就會被捕捉;
3) 捕捉訊號之後就會執行使用者自訂的一個訊號處理函數,並且在函數中調用系統函數去擷取資料;
4) 擷取資料同樣會將資料進行拷貝到使用者空間,這時進程或者線程仍然會被阻塞;
5) 當資料準備完畢同樣會通知使用者,之後就可以進行資料的處理了;
(5) asynchronous IO
對於非同步IO模型來說,資料的等待和搬遷都不由當前的進程或者線程來處理,調用相應系統函數之後就會直接返回繼續執行,因此目前使用者程並不會被阻塞,當資料已經在使用者空間準備就緒之後會以狀態、通知或者回調來告訴使用者可以進行資料的處理了:
1) 使用者程式調用aio_read函數,告訴核心描述字、緩衝區指標、緩衝區大小、檔案位移以及通知的方式,之後便立即返回;
2) 這時核心相應的資料操作組件會進行資料的等待和搬遷,期間使用者程式並不受影響繼續執行;
3) 當資料都已經在使用者空間準備就緒之後就會通過在函數中預留的通知方式來通知使用者程式處理資料;
總結:
從上面的分析中不難發現,在對於資料的擷取過程中都是進行了兩個主要的部分:資料的等待和資料的搬遷;除此相同點之外,下面就總結一下各種IO模型的區別:
從上面的比較可以發現:前四種IO模型也就是阻塞IO、非阻塞IO、IO複用和訊號驅動IO模型都是同步的,只有最後一種是非同步非同步IO模型;預設情況下所建立出來的socket都是以阻塞的形式,比如網路通訊中的recvfrom和sendto,或者read和write等函數都是以阻塞的方式來實現的。
參考:
Linux 中直接 I/O 機制的介紹
Linux之——五種IO模型 IO - 同步,非同步,阻塞,非阻塞
Linux network I/O