前言
學(xué)習(xí)Vert.x之前抢蚀,我們首先需要了解一下幾個(gè)概念医舆,Reactor設(shè)計(jì)模式就是其中一個(gè)炕柔。
一脑蠕、Reactor模式簡(jiǎn)介
? ? ? 我們知道對(duì)于應(yīng)用服務(wù)器购撼,通常會(huì)涉及到對(duì)文件系統(tǒng)、數(shù)據(jù)庫(kù)系統(tǒng)或者網(wǎng)絡(luò)進(jìn)行IO操作谴仙,由于cpu的運(yùn)行速度遠(yuǎn)大于IO的速度迂求,所以會(huì)發(fā)生這種情況:CPU可能會(huì)因?yàn)镮O的操作而阻塞。我們當(dāng)然不希望這種情況的發(fā)生晃跺,因?yàn)檫@大大降低了CPU的效率揩局,因此,引進(jìn)了多現(xiàn)程或多進(jìn)程進(jìn)行處理掀虎,即多個(gè)線(xiàn)程綁定多個(gè)IO事件凌盯,這樣雖然可以提高CPU的效率付枫,但仍然存在進(jìn)程切換帶來(lái)的弊端。
? ? ? ? 于是便引入了Reactor模式驰怎,首先励背,它是基于事件驅(qū)動(dòng),應(yīng)用服務(wù)首先向一個(gè)中間人注冊(cè)一個(gè)回調(diào)(event handler)進(jìn)行注冊(cè)砸西,然后中間人輪詢(xún)?cè)谄渖献?cè)過(guò)的服務(wù)叶眉,當(dāng)有IO就緒時(shí),中間人產(chǎn)生一個(gè)事件芹枷,并通知綁定的handler進(jìn)行處理衅疙,這種回調(diào)體現(xiàn)了"好萊塢原則"("Don’t call us, we’ll call you"),在IOC(控制反轉(zhuǎn))原則中也有相似的體現(xiàn)。這個(gè)中間人就是Reactor鸳慈。
? ? ? ? 通俗的來(lái)說(shuō)饱溢,在Reactor模式中,應(yīng)用程序不是主動(dòng)的調(diào)用某個(gè)API完成處理走芋,而是逆置了事件處理流程绩郎,應(yīng)用程序需要提供相應(yīng)的事件接口并注冊(cè)到Reactor上,如果相應(yīng)的事件發(fā)生翁逞,Reactor將主動(dòng)調(diào)用應(yīng)用程序注冊(cè)的接口肋杖,通過(guò)注冊(cè)的接口完成具體的事件處理。
二挖函、.模式組成及處理流程
1状植、模式組成
Reactor模式由事件源、事件反應(yīng)器怨喘、事件分離器津畸、事件處理器等組件組成。
事件源(handle):由操作系統(tǒng)提供必怜,用于識(shí)別每一個(gè)事件肉拓,如Socket描述符、文件描述符等梳庆。在服務(wù)端系統(tǒng)中用一個(gè)整數(shù)表示暖途。該事件可能來(lái)自外部,如來(lái)自客戶(hù)端的連接請(qǐng)求靠益、數(shù)據(jù)等丧肴。也可能來(lái)自?xún)?nèi)部,如定時(shí)器事件胧后。
事件反應(yīng)器(reactor):定義和應(yīng)用程序控制事件調(diào)度芋浮,以及應(yīng)用程序注冊(cè)、刪除事件處理器和相關(guān)描述符相關(guān)的接口。它是事件處理器的調(diào)度核心纸巷,使用事件分離器來(lái)等待事件的發(fā)生镇草。一旦事件發(fā)生,反應(yīng)器先是分離每個(gè)事件瘤旨,然后調(diào)度具體事件的事件處理器中的回調(diào)函數(shù)處理事件梯啤。
事件分離器(demultiplexer):是一個(gè)有操作系統(tǒng)提供的I/O復(fù)用函數(shù),在此我們選用epoll存哲。用來(lái)等待一個(gè)或多個(gè)事件的發(fā)生因宇。調(diào)用者將會(huì)被阻塞,直到分離器分離的描述符集上有事件發(fā)生祟偷。
事件處理器(even handler):事件處理程序提供了一組接口察滑,每個(gè)接口對(duì)應(yīng)了一種類(lèi)型的事件,供reactor在相應(yīng)的事件發(fā)生時(shí)調(diào)用修肠,執(zhí)行相應(yīng)的事件處理贺辰。一般每個(gè)具體的事件處理器總是會(huì)綁定一個(gè)有效的描述符句柄,用來(lái)識(shí)別事件和服務(wù)嵌施。
2饲化、處理流程
處理流程主要分為兩個(gè)部分,事件注冊(cè)部分和事件分發(fā)部分 吗伤;
下面具體看一下Reactor結(jié)構(gòu)圖
? ? ? 在事件注冊(cè)部分吃靠,應(yīng)用程序首先將期待注冊(cè)的套接字描述符作為事件源,并將描述符和該事件對(duì)應(yīng)的事件處理回調(diào)函數(shù)封裝到具體的事件處理器中牲芋,并將該事件處理器注冊(cè)到事件反應(yīng)器(Initialization Dispatcher)中撩笆。事件反應(yīng)器接收到事件后捺球,進(jìn)行相應(yīng)處理缸浦,并將注冊(cè)信息再次注冊(cè)到事件分離器epoll中。最后在epoll分離器中氮兵,通過(guò)epoll_ctl進(jìn)行添加描述符及其事件裂逐,并層層返回注冊(cè)結(jié)果。
? ? ? ?在事件處理部分泣栈,首先事件反應(yīng)器通過(guò)調(diào)用事件分離器的epoll_wait卜高,使線(xiàn)程阻塞等待注冊(cè)事件發(fā)生。此時(shí)如果某注冊(cè)事件發(fā)生南片,epoll_wait將會(huì)返回掺涛,并將包含該注冊(cè)事件在內(nèi)的事件集返回給事件反應(yīng)器。反應(yīng)器接收到該事件后疼进,根據(jù)該事件源找到該事件的事件處理器薪缆,并判斷事件類(lèi)型,根據(jù)事件類(lèi)型在該事件處理器調(diào)用之前注冊(cè)時(shí)封裝的具體回調(diào)函數(shù)伞广,在這個(gè)具體回調(diào)函數(shù)中完成事件處理拣帽。