事件驅動模式--Reactor
1 Reactor模型
Reactor模式是處理並發I/O比較常見的一種模式,用於同步I/O,中心思想是將所有要處理的I/O事件註冊到一個中心I/O多路復用器上,同時主線程/進程阻塞在多路復用器上;一旦有I/O事件到來或是準備就緒(文件描述符或socket可讀、寫),多路復用器返回並將事先註冊的相應I/O事件分發到對應的處理器中。
Reactor是一種事件驅動機制,和普通函數調用的不同之處在於:應用程序不是主動的調用某個API完成處理,而是恰恰相反,Reactor逆置了事件處理流程,應用程序需要提供相應的接口並註冊到Reactor上,如果相應的事件發生,Reactor將主動調用應用程序註冊的接口,這些接口又稱為“回調函數”。用“好萊塢原則
Reactor模式與Observer模式在某些方面極為相似:當一個主體發生改變時,所有依屬體都得到通知。不過,觀察者模式與單個事件源關聯,而反應器模式則與多個事件源關聯 。
Reactor模型各模塊之間的關系如下圖所示:
- Handle(描述符): 即操作系統中的句柄fd,是對資源在操作系統層面上的一種抽象,它可以是打開的文件、一個連接(Socket)、Timer等。將這個句柄fd註冊到Synchronous Event Demultiplexer中,以監聽Handle上發生的事件,可以是CONNECT事件,也可以是READ、WRITE、CLOSE事件等。
- Synchronous Event Demultiplexer(同步事件多路分離器): 阻塞等待被監聽的事件集fd_set中的事件發生。等待事件一般使用I/O復用技術實現,在linux系統上一般是select、poll、epol_waitl等系統調用,用來等待一個或多個事件的發生。I/O框架庫一般將各種I/O復用系統調用封裝成統一的接口,稱為事件多路分離器。調用者會被阻塞,直到分離器的描述符集上有事件發生。
- Initiation Dispatcher(啟動調度器):用於管理Event Handler,負責註冊、移除EventHandler等,如將EventHandler(事件處理器)註冊為響應fd對應事件的回調函數;另外,它還作為Reactor模式的入口,循環調用Synchronous Event Demultiplexer的select方法阻塞等待事件的發生;當阻塞等待返回時,根據事件發生的Handle將其分發給對應的Event Handler處理,即回調EventHandler中的handle_event()方法。
- Event Handler(事件處理器):I/O框架庫提供的事件處理器通常是由一個或多個模板函數組成的接口。這些模板函數描述了和應用程序相關的對某個事件的操作,用戶需要繼承它來實現自己的事件處理器,即具體事件處理器。因此,事件處理器中的回調函數一般聲明為虛函數,以支持用戶拓展。
- Concrete Event Handler(具體的事件處理器):是事件處理器接口的實現。它實現了應用程序提供的某個服務。每個具體的事件處理器總和一個描述符相關。它使用描述符來識別事件、識別應用程序提供的服務。
2 Reactor的幾種模式
在web服務中,很多都涉及基本的操作:read request、decode request、process service、encod reply、send reply等。
(1) 單線程模式
這是最簡單的單Reactor單線程模型。Reactor線程是個多面手,負責多路分離套接字,Accept新連接,並分派請求到處理器鏈中。該模型適用於處理器鏈中業務處理組件能快速完成的場景。不過這種單線程模型不能充分利用多核資源,所以實際使用的不多。
(2) 多線程模式(單Reactor)
該模型在事件處理器(Handler)鏈部分采用了多線程(線程池),也是後端程序常用的模型。
(3) 多線程模式(多個Reactor)
比起第二種模型,它是將Reactor分成兩部分,mainReactor負責監聽並accept新連接,然後將建立的socket通過多路復用器(Acceptor)分派給subReactor。subReactor負責多路分離已連接的socket,讀寫網絡數據;業務處理功能,其交給worker線程池完成。通常,subReactor個數上可與CPU個數等同。
參考:
Reactor - An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events
Scalable IO in Java
兩種高效的服務器設計模型:Reactor和Proactor模型
Reactor模式詳解
事件驅動模式--Reactor