兩種高效的事件處理模型:Reactor模式和Proactor模式


  隨着IO多路復用技術的出現,出現了很多事件處理模式。同步I/O模型通常由Reactor模式實現,而異步I/O模型則由Proactor模式實現。

 

  • Reactor模式:

 

  Reator類圖如上所示,Reactor模式又叫反應器或反應堆,即實現注冊描述符(Handle)及事件的處理器(EventHandler),當有事件發生的時候,事件多路分發器(Event Demultiplexer)做出反應,調用事件具體的處理函數(ConcreteEventHandler::handle_event())。

  Reator模式的典型啟動過程如下:

  1. 創建Reactor
  2. 注冊事件處理器(Reactor::register_handler())
  3. 調用事件多路分發器進入無限事件循環(Reacor:handle_events)
  4. 當操作系統通知某描述符狀態就緒時,事件多路分發器找出並調用此描述符注冊的事件處理器。

    Reactor模式已經被廣泛使用,著名的開源事件庫libevent、libev、libuv都是使用Reactor模式。

  Reactor模式的優點:

  • 實現相對簡單,對於耗時短的處理場景處理高效;
  • 操作系統可以在多個事件源上等待,並且避免了多線程編程相關的性能開銷和編程復雜性;
  • 事件的串行化對應用是透明的,可以順序的同步執行而不需要加鎖;
  • 事務分離:將與應用無關的多路分解和分配機制和與應用相關的回調函數分離開來。

  Reactor模式的缺點:

  Reactor處理耗時長的操作(如文件I/O)會造成事件分發的阻塞,影響到后續事件的處理。

  因此涉及到文件I/O相關的操作,需要使用異步I/O,即使用Proactor模式效果更佳。

 

  • Proactor模式

  Proactor模式的類圖如上圖所示,Proactor模式又叫前攝器或主動器模式。它用於實現異步I/O模型,運行流程如下:

  1. Initiator主動調用Asynchronous Operation Processor發起異步I/O操作,

  2. 記錄異步操作的參數和函數地址放入完成事件隊列(Completion Event Queue)中

  3. Proactor循環檢測異步事件是否完成。如果完成則從完成事件隊列中取出回調函數完成回調。

  Boost庫中的asio就使用了Proactor模式,其底層的異步I/O由操作系統提供,而異步事件的分發還是由epoll/kequeue/select等實現。

兩者區別

  綜上我們可以發現Reactor模式和Proactor模式的主要區別:

  1. Reactor實現同步I/O多路分發,Proactor實現異步I/O分發。

  如果只是處理網絡I/O單線程的Reactor尚可處理,但如果涉及到文件I/O,單線程的Reactor可能被文件I/O阻塞而導致其他事件無法被分發。所以涉及到文件I/O最好還是使用Proactor模式,或者用多線程模擬實現異步I/O的方式。

  2. Reactor模式注冊的是文件描述符的就緒事件,而Proactor模式注冊的是完成事件。

  即Reactor模式有事件發生的時候要判斷是讀事件還是寫事件,然后用再調用系統調用(read/write等)將數據從內核中拷貝到用戶數據區繼續其他業務處理。

  而Proactor模式一般使用的是操作系統的異步I/O接口,發起異步調用(用戶提供數據緩沖區)之后操作系統將在內核態完成I/O並拷貝數據到用戶提供的緩沖區中,完成事件到達之后,用戶只需要實現自己后續的業務處理即可。

  3. 主動和被動

  Reactor模式是一種被動的處理,即有事件發生時被動處理。而Proator模式則是主動發起異步調用,然后循環檢測完成事件。

  

  最后我們知道linux系統提供的異步I/O,只支持O_DIRECT,不能帶緩存。因此出現了開源庫libeio,它和Linux的異步I/O一樣也是用多線程模擬,但是更高效。下圖是libeio的異步I/O實現,是不是很像Proactor模式啊。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM