Java IO篇:什么是 Proactor 网络模型?
一、Proactor出現的背景:
? ? ? ? 前面我們介紹了 Reactor 網絡模型(文章地址:https://blog.csdn.net/a745233700/article/details/122660246),知道了 Reactor 是非阻塞同步網絡模型,而 Proactor 是異步網絡模型。
(1)對于阻塞IO,當用戶程序執行 read,線程會被阻塞,一直等內核數據準備好,并把數據從內核緩沖區拷貝到應用程序的緩沖區中,當拷貝過程完成,read 才會返回。如下圖:
阻塞等待的是「內核數據準備好」和「數據從內核態拷貝到用戶態」這兩個過程
?(2)對于非阻塞IO,非阻塞的read請求在數據未準備好的情況下立即返回,可以繼續往下執行,此時應用程序不斷輪詢內核,直到數據準備好,內核將數據拷貝到應用程序緩沖區,read 調用才可以獲取到結果。過程如下圖:
這里最后一次 read 調用,獲取數據的過程,是一個同步的過程,是需要等待的過程。這里的同步指的是內核態的數據拷貝到用戶程序的緩存區這個過程。
????????因此,無論 read 和 send 是阻塞 I/O,還是非阻塞 I/O 都是同步調用。因為在 read 調用時,內核將數據從內核空間拷貝到用戶空間的過程都是需要等待的,也就是說這個過程是同步的,如果內核實現的拷貝效率不高,read 調用就會在這個同步過程中等待比較長的時間。
(3)對于異步IO,指的是「內核數據準備好」和「數據從內核態拷貝到用戶態」這兩個過程都不用等待。當我們發起 aio_read (異步 I/O) 之后,就立即返回,內核自動將數據從內核空間拷貝到用戶空間,這個拷貝過程同樣是異步的,內核自動完成的,和前面的同步操作不一樣,應用程序并不需要主動發起拷貝動作。過程如下圖:
????????Proactor 正是使用了異步 I/O 技術,所以被稱為異步網絡模型。現在我們再來理解 Reactor 和 Proactor 的區別,就比較清晰了:
- Reactor 是同步非阻塞網絡模型,感知的是就緒可讀寫事件。在每次感知到有事件發生(比如可讀就緒事件)后,就需要應用進程主動調用 read 方法來完成數據的讀取,也就是要應用進程主動將 socket 接收緩存中的數據讀到應用進程內存中,這個過程是同步的,讀取完數據后應用進程才能處理數據。
- Proactor 是異步網絡模式, 感知的是已完成的讀寫事件。在發起異步讀寫請求時,需要傳入數據緩沖區的地址(用來存放結果數據)等信息,這樣系統內核才可以自動幫我們把數據的讀寫工作完成,這里的讀寫工作全程由操作系統來做,并不需要像 Reactor 那樣還需要應用進程主動發起 read/write 來讀寫數據,操作系統完成讀寫工作后,就會通知應用進程直接處理數據。
????????因此,Reactor 可以理解為「來了事件操作系統通知應用進程,讓應用進程來處理」,而 Proactor 可以理解為「來了事件操作系統來處理,處理完再通知應用進程」。這里的「事件」就是有新連接、有數據可讀、有數據可寫的這些 I/O 事件這里的「處理」包含從驅動讀取到內核以及從內核讀取到用戶空間。
????????舉個實際生活中的例子,Reactor 模式就是快遞員在樓下,給你打電話告訴你快遞到你家小區了,你需要自己下樓來拿快遞。而在 Proactor 模式下,快遞員直接將快遞送到你家門口,然后通知你。
? ? ? ? 從上面介紹的內容我們不難看出 Proactor 產生的主要原因:Reactor 性能確實非常高,適合高并發場景,但它依然存在一個問題,那就是它是同步IO。同步IO需要線程自己等待內核準備好數據,在內核準備數據的過程中,當前線程是阻塞的,這樣就會導致如果某個線程因為讀取IO的時間過長(比如讀取文件、寫文件),則它勢必會影響其他線程的執行。
二、Proactor 的執行流程:
????????無論是 Reactor,還是 Proactor,都是一種基于「事件分發」的網絡編程模式,區別在于 Reactor 模式是基于「待完成」的 I/O 事件,而 Proactor 模式則是基于「已完成」的 I/O 事件。接下來,一起看看 Proactor 模式的示意圖:
介紹一下 Proactor 模式的工作流程:
- Proactor Initiator 負責創建 Proactor 和 Handler 對象,并將 Proactor 和 Handler 都通過? Asynchronous Operation Processor 注冊到內核;
- Asynchronous Operation Processor 負責處理注冊請求,并處理 I/O 操作;
- Asynchronous Operation Processor 完成 I/O 操作后通知 Proactor;
- Proactor 根據不同的事件類型回調不同的 Handler 進行業務處理;
- Handler 完成業務處理;
需要注意的是:Proactor關注的不是就緒事件,而是完成事件,這是區分Reactor模式的關鍵點。
下面就簡單介紹下?Proactor 模型處理讀取操作的主要流程:
- (1)應用程序初始化一個異步讀取操作,然后注冊相應的事件處理器,此時事件處理器不關注讀取就緒事件,而是關注讀取完成事件,這是區別于Reactor的關鍵。
- (2)事件分離器等待讀取操作完成事件
- (3)在事件分離器等待讀取操作完成的時候,操作系統調用內核線程完成讀取操作,并將讀取的內容放入用戶傳遞過來的緩存區中。這也是區別于Reactor的一點,Proactor中,應用程序需要傳遞緩存區。
- (4)事件分離器捕獲到讀取完成事件后,激活應用程序注冊的事件處理器,事件處理器直接從緩存區讀取數據,而不需要進行實際的讀取操作。
異步IO都是操作系統負責將數據讀寫到應用傳遞進來的緩沖區供應用程序操作。
Proactor中寫入操作和讀取操作基本一致,只不過監聽的事件是寫入完成事件而已。
三、Proactor 的缺點:
Proactor 性能確實非常強大,效率也高,但是同樣存在以下缺點:
(1)內存的使用:緩沖區在讀或寫操作的時間段內必須保持住,可能造成持續的不確定性,并且每個并發操作都要求有獨立的緩存,相比Reactor模型,在Socket已經準備好讀或寫前,是不要求開辟緩存的;
(2)操作系統的支持:Windows 下通過一套完整的支持 socket 的異步編程接口,也就是通過?IOCP 實現了真正的異步,但 Linux 系統下的異步 IO 還不完善,aio 系列函數是由 POSIX 定義的異步操作接口,不是真正的操作系統級別支持的,而是在用戶空間模擬出來的異步,并且僅僅支持基于本地文件的 aio 異步操作,網絡編程中的 socket 是不支持的。因此,Linux 系統下高并發網絡編程都是以?Reactor 模型為主
參考文章:
https://blog.csdn.net/qq_34827674/article/details/116175772
https://cloud.tencent.com/developer/article/1488120
總結
以上是生活随笔為你收集整理的Java IO篇:什么是 Proactor 网络模型?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常见分布式理论(CAP、BASE)和一致
- 下一篇: 什么是RPC?RPC框架dubbo的核心