事件驅(qū)動機(jī)制與Reactor模型

通常,我們寫服務(wù)器處理模型的程序時,有以下幾種模型:

(1)每收到一個請求,創(chuàng)建一個新的進(jìn)程,來處理該請求;

(2)每收到一個請求,創(chuàng)建一個新的線程,來處理該請求;

(3)每收到一個請求,放入一個事件列表,讓主進(jìn)程通過非阻塞I/O方式來處理請求

上面的幾種方式,各有千秋,

第(1)中方法,由于創(chuàng)建新的進(jìn)程的開銷比較大,所以,會導(dǎo)致服務(wù)器性能比較差,但實(shí)現(xiàn)比較簡單。

第(2)種方式,由于要涉及到線程的同步,有可能會面臨死鎖等問題。

第(3)種方式,在寫應(yīng)用程序代碼時,邏輯比前面兩種都復(fù)雜。

綜合考慮各方面因素,一般普遍認(rèn)為第(3)種方式是大多數(shù)網(wǎng)絡(luò)服務(wù)器采用的方式。

什么是事件驅(qū)動機(jī)制?

1.要理解事件驅(qū)動和程序,就需要與非事件驅(qū)動的程序進(jìn)行比較。實(shí)際上,現(xiàn)代的程序大多是事件驅(qū)動的,比如多線程的程序,肯定是事件驅(qū)動的。早期則存在許多非事件驅(qū)動的程序,這樣的程序,在需要等待某個條件觸發(fā)時,會不斷地檢查這個條件,直到條件滿足,這是很浪費(fèi)cpu時間的。而事件驅(qū)動的程序,則有機(jī)會釋放cpu從而進(jìn)入睡眠態(tài)(注意是有機(jī)會,當(dāng)然程序也可自行決定不釋放cpu),當(dāng)事件觸發(fā)時被操作系統(tǒng)喚醒,這樣就能更加有效地使用cpu.

2.再說什么是事件驅(qū)動的程序。一個典型的事件驅(qū)動的程序,就是一個死循環(huán),并以一個線程的形式存在,這個死循環(huán)包括兩個部分,第一個部分是按照一定的條件接收并選擇一個要處理的事件,第二個部分就是事件的處理過程。程序的執(zhí)行過程就是選擇事件和處理事件,而當(dāng)沒有任何事件觸發(fā)時,程序會因查詢事件隊(duì)列失敗而進(jìn)入睡眠狀態(tài),從而釋放cpu。

3.事件驅(qū)動的程序,必定會直接或者間接擁有一個事件隊(duì)列,用于存儲未能及時處理的事件。

4.事件驅(qū)動的程序的行為,完全受外部輸入的事件控制,所以,事件驅(qū)動的系統(tǒng)中,存在大量這種程序,并以事件作為主要的通信方式。

5.事件驅(qū)動的程序,還有一個最大的好處,就是可以按照一定的順序處理隊(duì)列中的事件,而這個順序則是由事件的觸發(fā)順序決定的,這一特性往往被用于保證某些過程的原子化。

事件驅(qū)動機(jī)制與IO多路復(fù)用有什么關(guān)系?

I/O多路復(fù)用可以用作并發(fā)事件驅(qū)動(event-driven)程序的基礎(chǔ),即整個事件驅(qū)動模型是一個狀態(tài)機(jī),包含了狀態(tài)(state), 輸入事件(input-event), 狀態(tài)轉(zhuǎn)移(transition), 狀態(tài)轉(zhuǎn)移即狀態(tài)到輸入事件的一組映射。通過I/O多路復(fù)用的技術(shù)檢測事件的發(fā)生,并根據(jù)具體的事件(通常為讀寫),進(jìn)行不同的操作,即狀態(tài)轉(zhuǎn)移。

如何結(jié)合事件模型使用NIO同步非阻塞特性?

回憶BIO模型,之所以需要多線程,是因?yàn)樵谶M(jìn)行I/O操作的時候,一是沒有辦法知道到底能不能寫、能不能讀,只能"傻等",即使通過各種估算,算出來操作系統(tǒng)沒有能力進(jìn)行讀寫,也沒法在socket.read()和socket.write()函數(shù)中返回,這兩個函數(shù)無法進(jìn)行有效的中斷。所以除了多開線程另起爐灶,沒有好的辦法利用CPU。

NIO的讀寫函數(shù)可以立刻返回,這就給了我們不開線程利用CPU的最好機(jī)會:如果一個連接不能讀寫(socket.read()返回0或者socket.write()返回0),我們可以把這件事記下來,記錄的方式通常是在Selector上注冊標(biāo)記位,然后切換到其它就緒的連接(channel)繼續(xù)進(jìn)行讀寫。

下面具體看下如何利用事件模型單線程處理所有I/O請求:

NIO的主要事件有幾個:讀就緒、寫就緒、有新連接到來。

我們首先需要注冊當(dāng)這幾個事件到來的時候所對應(yīng)的處理器。然后在合適的時機(jī)告訴事件選擇器:我對這個事件感興趣。對于寫操作,就是寫不出去的時候?qū)懯录信d趣;對于讀操作,就是完成連接和系統(tǒng)沒有辦法承載新讀入的數(shù)據(jù)的時;對于accept,一般是服務(wù)器剛啟動的時候;而對于connect,一般是connect失敗需要重連或者直接異步調(diào)用connect的時候。

其次,用一個死循環(huán)選擇就緒的事件,會執(zhí)行系統(tǒng)調(diào)用(Linux 2.6之前是select、poll,2.6之后是epoll,Windows是IOCP),還會阻塞的等待新事件的到來。新事件到來的時候,會在selector上注冊標(biāo)記位,標(biāo)示可讀、可寫或者有連接到來。

注意,select是阻塞的,無論是通過操作系統(tǒng)的通知(epoll)還是不停的輪詢(select,poll),這個函數(shù)是阻塞的。所以你可以放心大膽地在一個while(true)里面調(diào)用這個函數(shù)而不用擔(dān)心CPU空轉(zhuǎn)。

什么是事件(事件源)?

linux上為文件描述符,handler即為注冊在特定事件上的程序,事件發(fā)生通常在linux下為I/O事件,由操作系統(tǒng)觸發(fā)。

什么是Reactor (反應(yīng)器)?

事件管理的接口,內(nèi)部使用event demultiplexer注冊,注銷事件;并運(yùn)行事件循環(huán),當(dāng)有事件進(jìn)入"就緒"狀態(tài)時,調(diào)用注冊事件的回調(diào)函數(shù)處理事件。

什么是Event demultiplexer(事件多路分發(fā)機(jī)制)?

通常是由操作系統(tǒng)提供的I/O多路復(fù)用的機(jī)制,例如select,?epoll. 程序首先將handler(事件源)以及對應(yīng)的事件注冊到event demultiplexer上;當(dāng)有事件到達(dá)時,event demultiplexer就會發(fā)出通知,通知Reactor調(diào)用事件處理程序進(jìn)行處理。

一般情況下,I/O 復(fù)用機(jī)制需要事件分發(fā)器(event dispatcher)。

事件分發(fā)器的作用,即將那些讀寫事件源分發(fā)給各讀寫事件的處理者,就像送快遞的在樓下喊: 誰誰誰的快遞到了, 快來拿吧!開發(fā)人員在開始的時候需要在分發(fā)器那里注冊感興趣的事件,并提供相應(yīng)的處理者(event handler),或者是回調(diào)函數(shù);事件分發(fā)器在適當(dāng)?shù)臅r候,會將請求的事件分發(fā)給這些handler或者回調(diào)函數(shù)。涉及到事件分發(fā)器的兩種模式稱為:Reactor和Proactor。

什么是Event Handler(事件處理程序)?

事件處理程序提供了一組接口,在Reactor相應(yīng)的事件發(fā)生時調(diào)用,執(zhí)行相應(yīng)的事件處理,通常會綁定一個有效的handler。

什么是Reactor模型?

Reactor模式是一種典型的事件驅(qū)動的編程模型,Reactor逆置了程序處理的流程,其基本的思想即為Hollywood Principle— 'Don't call us, we'll call you'.

普通的函數(shù)處理機(jī)制為:調(diào)用某函數(shù)-> 函數(shù)執(zhí)行, 主程序等待阻塞-> 函數(shù)將結(jié)果返回給主程序-> 主程序繼續(xù)執(zhí)行。

Reactor事件處理機(jī)制為:主程序?qū)⑹录约皩?yīng)事件處理的方法在Reactor上進(jìn)行注冊, 如果相應(yīng)的事件發(fā)生,Reactor將會主動調(diào)用事件注冊的接口,即回調(diào)函數(shù).?libevent即為封裝了epoll并注冊相應(yīng)的事件(I/O讀寫,時間事件,信號事件)以及回調(diào)函數(shù),實(shí)現(xiàn)的事件驅(qū)動的框架。

Reactor架構(gòu)模式允許事件驅(qū)動的應(yīng)用通過多路分發(fā)的機(jī)制去處理來自不同客戶端的多個請求。事件(事件源)、Reactor (反應(yīng)器)、Event demultiplexer(事件多路分發(fā)機(jī)制)、Event Handler(事件處理程序)是Reactor架構(gòu)模式的關(guān)鍵組件。Reactor核心的事件處理流程如圖所示:


什么是好萊塢原則?

在網(wǎng)絡(luò)編程中,特別是server端編程時,我們可能會大量利用好萊塢原則。在server端編程時,我們大多會利用OS提供的一些功能強(qiáng)大的時間分派機(jī)制,比如select/ poll/ epoll/ WaitForMultipleObjects等,通過對這些機(jī)制的再次包裝和抽象,牛人們提出了著名的reactor模式(中文翻譯成反應(yīng)堆模式)。在此模式中,我們使用者不用關(guān)心以下事情:

  1)socket什么時候建立連接

  2)socket什么時候有數(shù)據(jù)帶來

  3)socket什么時候把數(shù)據(jù)發(fā)送

  4)socket什么時候斷開連接

  我們關(guān)心的是這些事件帶來的時候,我們怎么處理?比如socket建立連接了,你是否要做一些log,以便以后查看。收到數(shù)據(jù)之后,你是否要做完整性驗(yàn)證等。我們不用關(guān)心事件怎么來(HOW),什么時候來(WHEN),我們關(guān)心的唯一一件事是處理它(Do it)。在這里如果把reactor等抽象系統(tǒng)(reactor模型)比喻成好萊塢的話,網(wǎng)絡(luò)上的數(shù)據(jù)/事件比喻成影片或劇本的話,我們可以把我們對數(shù)據(jù)的處理(對應(yīng)數(shù)據(jù)/事件的處理方法)比喻成演員。這里,演員(對應(yīng)數(shù)據(jù)/事件的處理方法)不用去找劇本(數(shù)據(jù)/事件),好萊塢(reactor模型)會帶著劇本(數(shù)據(jù))來找你,你只要乖乖著等在家里不要亂動,等劇本(數(shù)據(jù))來了,你給我好好處理即可。

事件管理的接口,內(nèi)部使用event demultiplexer注冊,注銷事件;并運(yùn)行事件循環(huán),當(dāng)有事件進(jìn)入"就緒"狀態(tài)時,調(diào)用注冊事件的回調(diào)函數(shù)處理事件。

通常是由操作系統(tǒng)提供的I/O多路復(fù)用的機(jī)制,例如select,?epoll. 程序首先將handler(事件源)以及對應(yīng)的事件注冊到event demultiplexer上;當(dāng)有事件到達(dá)時,event demultiplexer就會發(fā)出通知,通知Reactor調(diào)用事件處理程序進(jìn)行處理。

事件處理程序提供了一組接口,在Reactor相應(yīng)的事件發(fā)生時調(diào)用,執(zhí)行相應(yīng)的事件處理,通常會綁定一個有效的handler。

怎樣在Reactor中實(shí)現(xiàn)讀?

①?注冊讀就緒事件和相應(yīng)的事件處理器。

②事件分發(fā)器等待事件。

③事件到來,激活分發(fā)器,分發(fā)器調(diào)用事件對應(yīng)的處理器。

④事件處理器完成實(shí)際的讀操作,處理讀到的數(shù)據(jù),注冊新的事件,然后返還控制權(quán)。

標(biāo)準(zhǔn)/典型的Reactor是什么?

步驟1:等待事件到來(Reactor負(fù)責(zé))。

步驟2:將讀就緒事件分發(fā)給用戶定義的處理器(Reactor負(fù)責(zé))。

步驟3:讀數(shù)據(jù)(用戶處理器負(fù)責(zé))。

步驟4:處理數(shù)據(jù)(用戶處理器負(fù)責(zé))。

Reactor模式流程是什么?

① 初始化Initiation Dispatcher,然后將若干個Concrete Event Handler注冊到Initiation Dispatcher中。當(dāng)應(yīng)用向Initiation Dispatcher注冊Concrete Event Handler時,會在注冊的同時指定感興趣的事件,即,應(yīng)用會標(biāo)識出該事件處理器希望Initiation Dispatcher在某些事件發(fā)生時向其發(fā)出通知,事件通過Handle來標(biāo)識,而Concrete Event Handler又持有該Handle。這樣,事件 —> Handle —> Concrete Event Handler 就關(guān)聯(lián)起來了。

② Initiation Dispatcher 會要求每個事件處理器向其傳遞內(nèi)部的Handle。該Handle向操作系統(tǒng)標(biāo)識了事件處理器。

③ 當(dāng)所有的Concrete Event Handler都注冊完畢后,應(yīng)用會調(diào)用handle_events方法來啟動Initiation Dispatcher的事件循環(huán)。這是,Initiation Dispatcher會將每個注冊的Concrete Event Handler的Handle合并起來,并使用Synchronous Event Demultiplexer(同步事件分離器)同步阻塞的等待事件的發(fā)生。比如說,TCP協(xié)議層會使用select同步事件分離器操作來等待客戶端發(fā)送的數(shù)據(jù)到達(dá)連接的socket handler上。

比如,在Java中通過Selector的select()方法來實(shí)現(xiàn)這個同步阻塞等待事件發(fā)生的操作。在Linux操作系統(tǒng)下,select()的實(shí)現(xiàn)中 a)會將已經(jīng)注冊到Initiation Dispatcher的事件調(diào)用epollCtl(epfd, opcode, fd, events)注冊到linux系統(tǒng)中,這里fd表示Handle,events表示我們所感興趣的Handle的事件;b)通過調(diào)用epollWait方法同步阻塞的等待已經(jīng)注冊的事件的發(fā)生。不同事件源上的事件可能同時發(fā)生,一旦有事件被觸發(fā)了,epollWait方法就會返回;c)最后通過發(fā)生的事件找到相關(guān)聯(lián)的SelectorKeyImpl對象,并設(shè)置其發(fā)生的事件為就緒狀態(tài),然后將SelectorKeyImpl放入selectedSet中。這樣一來我們就可以通過Selector.selectedKeys()方法得到事件就緒的SelectorKeyImpl集合了。

④ 當(dāng)與某個事件源對應(yīng)的Handle變?yōu)閞eady狀態(tài)時(比如說,TCP socket變?yōu)榈却x狀態(tài)時),Synchronous Event Demultiplexer就會通知Initiation Dispatcher。

⑤ Initiation Dispatcher會觸發(fā)事件處理器的回調(diào)方法,從而響應(yīng)這個處于ready狀態(tài)的Handle。當(dāng)事件發(fā)生時,Initiation Dispatcher會將被事件源激活的Handle作為『key』來尋找并分發(fā)恰當(dāng)?shù)氖录幚砥骰卣{(diào)方法。

⑥ Initiation Dispatcher會回調(diào)事件處理器的handle_event(type)回調(diào)方法來執(zhí)行特定于應(yīng)用的功能(開發(fā)者自己所編寫的功能),從而相應(yīng)這個事件。所發(fā)生的事件類型可以作為該方法參數(shù)并被該方法內(nèi)部使用來執(zhí)行額外的特定于服務(wù)的分離與分發(fā)。

Reactor模式的實(shí)現(xiàn)方式有哪些?

1. 單線程Reactor模式:

流程:

① 服務(wù)器端的Reactor是一個線程對象,該線程會啟動事件循環(huán),并使用Selector來實(shí)現(xiàn)IO的多路復(fù)用。注冊一個Acceptor事件處理器到Reactor中,Acceptor事件處理器所關(guān)注的事件是ACCEPT事件,這樣Reactor會監(jiān)聽客戶端向服務(wù)器端發(fā)起的連接請求事件(ACCEPT事件)。

② 客戶端向服務(wù)器端發(fā)起一個連接請求,Reactor監(jiān)聽到了該ACCEPT事件的發(fā)生并將該ACCEPT事件派發(fā)給相應(yīng)的Acceptor處理器來進(jìn)行處理。Acceptor處理器通過accept()方法得到與這個客戶端對應(yīng)的連接(SocketChannel),然后將該連接所關(guān)注的READ事件以及對應(yīng)的READ事件處理器注冊到Reactor中,這樣一來Reactor就會監(jiān)聽該連接的READ事件了?;蛘弋?dāng)你需要向客戶端發(fā)送數(shù)據(jù)時,就向Reactor注冊該連接的WRITE事件和其處理器。

③ 當(dāng)Reactor監(jiān)聽到有讀或者寫事件發(fā)生時,將相關(guān)的事件派發(fā)給對應(yīng)的處理器進(jìn)行處理。比如,讀處理器會通過SocketChannel的read()方法讀取數(shù)據(jù),此時read()操作可以直接讀取到數(shù)據(jù),而不會堵塞與等待可讀的數(shù)據(jù)到來。

④ 每當(dāng)處理完所有就緒的感興趣的I/O事件后,Reactor線程會再次執(zhí)行select()阻塞等待新的事件就緒并將其分派給對應(yīng)處理器進(jìn)行處理。

注意,Reactor的單線程模式的單線程主要是針對于I/O操作而言,也就是所以的I/O的accept()、read()、write()以及connect()操作都在一個線程上完成的。

但在目前的單線程Reactor模式中,不僅I/O操作在該Reactor線程上,連非I/O的業(yè)務(wù)操作也在該線程上進(jìn)行處理了,這可能會大大延遲I/O請求的響應(yīng)。所以我們應(yīng)該將非I/O的業(yè)務(wù)邏輯操作從Reactor線程上卸載,以此來加速Reactor線程對I/O請求的響應(yīng)。

2.?單線程Reactor模式的改進(jìn),使用工作者線程池

由上面的示例我們大概可以總結(jié)出NIO是怎么解決掉線程的瓶頸并處理海量連接的:

NIO由原來的阻塞讀寫(占用線程)變成了單線程輪詢事件,找到可以進(jìn)行讀寫的網(wǎng)絡(luò)描述符進(jìn)行讀寫。除了事件的輪詢是阻塞的(沒有可干的事情必須要阻塞),剩余的I/O操作都是純CPU操作,沒有必要開啟多線程。

并且由于線程的節(jié)約,連接數(shù)大的時候因?yàn)榫€程切換帶來的問題也隨之解決,進(jìn)而為處理海量連接提供了可能。

單線程處理I/O的效率確實(shí)非常高,沒有線程切換,只是拼命的讀、寫、選擇事件。但現(xiàn)在的服務(wù)器,一般都是多核處理器,如果能夠利用多核心進(jìn)行I/O,無疑對效率會有更大的提高。

仔細(xì)分析一下我們需要的線程,其實(shí)主要包括以下幾種:

事件分發(fā)器,單線程選擇就緒的事件。

I/O處理器,包括connect、read、write等,這種純CPU操作,一般開啟CPU核心個線程就可以。

業(yè)務(wù)線程,在處理完I/O后,業(yè)務(wù)一般還會有自己的業(yè)務(wù)邏輯,有的還會有其他的阻塞I/O,如DB操作,RPC等。只要有阻塞,就需要單獨(dú)的線程。

Java的Selector對于Linux系統(tǒng)來說,有一個致命限制:同一個channel的select不能被并發(fā)的調(diào)用。因此,如果有多個I/O線程,必須保證:一個socket只能屬于一個IoThread,而一個IoThread可以管理多個socket。

另外連接的處理和讀寫的處理通??梢赃x擇分開,這樣對于海量連接的注冊和讀寫就可以分發(fā)。雖然read()和write()是比較高效無阻塞的函數(shù),但畢竟會占用CPU,如果面對更高的并發(fā)則無能為力。

與單線程Reactor模式不同的是,添加了一個工作者線程池,并將非I/O操作從Reactor線程中移出轉(zhuǎn)交給工作者線程池來執(zhí)行。這樣能夠提高Reactor線程的I/O響應(yīng),不至于因?yàn)橐恍┖臅r的業(yè)務(wù)邏輯而延遲對后面I/O請求的處理。

使用線程池的優(yōu)勢:

① 通過重用現(xiàn)有的線程而不是創(chuàng)建新線程,可以在處理多個請求時分?jǐn)傇诰€程創(chuàng)建和銷毀過程產(chǎn)生的巨大開銷。

② 另一個額外的好處是,當(dāng)請求到達(dá)時,工作線程通常已經(jīng)存在,因此不會由于等待創(chuàng)建線程而延遲任務(wù)的執(zhí)行,從而提高了響應(yīng)性。

③ 通過適當(dāng)調(diào)整線程池的大小,可以創(chuàng)建足夠多的線程以便使處理器保持忙碌狀態(tài)。同時還可以防止過多線程相互競爭資源而使應(yīng)用程序耗盡內(nèi)存或失敗。

注意,在上圖的改進(jìn)的版本中,所有的I/O操作依舊由一個Reactor來完成,包括I/O的accept()、read()、write()以及connect()操作。

對于一些小容量應(yīng)用場景,可以使用單線程模型。但是對于高負(fù)載、大并發(fā)或大數(shù)據(jù)量的應(yīng)用場景卻不合適,主要原因如下:

① 一個NIO線程同時處理成百上千的鏈路,性能上無法支撐,即便NIO線程的CPU負(fù)荷達(dá)到100%,也無法滿足海量消息的讀取和發(fā)送;

② 當(dāng)NIO線程負(fù)載過重之后,處理速度將變慢,這會導(dǎo)致大量客戶端連接超時,超時之后往往會進(jìn)行重發(fā),這更加重了NIO線程的負(fù)載,最終會導(dǎo)致大量消息積壓和處理超時,成為系統(tǒng)的性能瓶頸;

3. 多Reactor線程模式

Reactor線程池中的每一Reactor線程都會有自己的Selector、線程和分發(fā)的事件循環(huán)邏輯。mainReactor可以只有一個,但subReactor一般會有多個。mainReactor線程主要負(fù)責(zé)接收客戶端的連接請求,然后將接收到的SocketChannel傳遞給subReactor,由subReactor來完成和客戶端的通信。

流程:

① 注冊一個Acceptor事件處理器到mainReactor中,Acceptor事件處理器所關(guān)注的事件是ACCEPT事件,這樣mainReactor會監(jiān)聽客戶端向服務(wù)器端發(fā)起的連接請求事件(ACCEPT事件)。啟動mainReactor的事件循環(huán)。

② 客戶端向服務(wù)器端發(fā)起一個連接請求,mainReactor監(jiān)聽到了該ACCEPT事件并將該ACCEPT事件派發(fā)給Acceptor處理器來進(jìn)行處理。Acceptor處理器通過accept()方法得到與這個客戶端對應(yīng)的連接(SocketChannel),然后將這個SocketChannel傳遞給subReactor線程池。

③ subReactor線程池分配一個subReactor線程給這個SocketChannel,即,將SocketChannel關(guān)注的READ事件以及對應(yīng)的READ事件處理器注冊到subReactor線程中。當(dāng)然你也注冊WRITE事件以及WRITE事件處理器到subReactor線程中以完成I/O寫操作。Reactor線程池中的每一Reactor線程都會有自己的Selector、線程和分發(fā)的循環(huán)邏輯。

④ 當(dāng)有I/O事件就緒時,相關(guān)的subReactor就將事件派發(fā)給相應(yīng)的處理器處理。注意,這里subReactor線程只負(fù)責(zé)完成I/O的read()操作,在讀取到數(shù)據(jù)后將業(yè)務(wù)邏輯的處理放入到線程池中完成,若完成業(yè)務(wù)邏輯后需要返回數(shù)據(jù)給客戶端,則相關(guān)的I/O的write操作還是會被提交回subReactor線程來完成。

注意,所有的I/O操作(包括,I/O的accept()、read()、write()以及connect()操作)依舊還是在Reactor線程(mainReactor線程 或 subReactor線程)中完成的。Thread Pool(線程池)僅用來處理非I/O操作的邏輯。

多Reactor線程模式將“接受客戶端的連接請求”和“與該客戶端的通信”分在了兩個Reactor線程來完成。mainReactor完成接收客戶端連接請求的操作,它不負(fù)責(zé)與客戶端的通信,而是將建立好的連接轉(zhuǎn)交給subReactor線程來完成與客戶端的通信,這樣一來就不會因?yàn)閞ead()數(shù)據(jù)量太大而導(dǎo)致后面的客戶端連接請求得不到即時處理的情況。并且多Reactor線程模式在海量的客戶端并發(fā)請求的情況下,還可以通過實(shí)現(xiàn)subReactor線程池來將海量的連接分發(fā)給多個subReactor線程,在多核的操作系統(tǒng)中這能大大提升應(yīng)用的負(fù)載和吞吐量。

參考鏈接:

Java NIO淺析 - 知乎

深入理解Reactor 網(wǎng)絡(luò)編程模型 - 知乎

Reactor模式詳解 - winner_0715 - 博客園

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容