---
# System prepended metadata

title: Reactor vs Proactor
tags: [Research]

---

---
tags: Research 
---
# Reactor vs Proactor
## Reactor
I/O 事件加到 multiplexer 中輪詢，當 I/O 事件 ready，multiplexer 會將 I/O 事件送給註冊該事件的 Handler 處理。(有事先註冊事件對應的 Handler)

* single Reactor and single-thread
Reactor 模式主要由 Reactor 和處理資源池這兩個核心部分組成
    * Reactor(dispatch) 負責監聽和分發事件，事件類型包含連接事件(派給 acceptor)、讀寫事件(派給 Handler)
    * Acceptor: 處理連接事件
    * Handler: 處理 Read/Write I/O 事件，如 read -> 處理資料 -> send
    
* single Reactor and multi-thread
    * Handler 不再處理資料，只負責做 Read/Write I/O 操作，Handler 對象通過 read 讀取到資料後，會將資料發給 thread pool 中的執行緒，這些執行緒負責處理資料，處理完後，將結果發給 main thread 中的 Handler，Handler 收到資料通過 send 將結果發送給 client。

單 Reactor 模式還有個問題，因為一個 Reactor 對象承擔所有事件的監聽和 response，而且只在 main thread 中運行，在面對瞬間高 concurrency 的場景時，容易遇到效能瓶頸。
* multi-Reactor and multi-thread
    * main thread 中的 MainReactor 通過 select 監聽 connection 事件，收到事件後通過 Acceptor 中的 accept 獲取連接，將新的連接分配給子執行緒。
    * 子執行緒中的 SubReactor 將 MainReactor accept 後的 connection 加入 select 繼續進行監聽，並建立一個 Handler 用於處理 Read/Write I/O 操作。
    * 如果有新的事件發生時，SubReactor 會呼叫對應的 Handler。 Handler 通過 read -> 處理資料 -> send 的流程來完成處理資料。 
    
## Proactor
Hanlder 直接進行 asynchronous I/O 操作，將 asynchronous I/O 操作交由 kernel thread 處理，kernel thread 處理完成後會發 signal 通知 multiplexer，multiplexer 再通知 handler。

## Conclusion
* Reactor 是 non-blocking synchronous I/O 模式，透過就緒 (Ready) 可讀寫事件觸發。每次到有事件發生（比如可讀就緒事件）後，就需要 application 主動調用 read 方法來完成資料的讀取，也就是要 application 主動將 socket receiving buffer 中的資料讀到 application memory 中，這個過程是同步的，讀取完資料後才能進一步處理資料。 
* Proactor 是 asynchronous I/O 模式，透過已完成的讀寫事件(kernel thread 已經讀到 userspace 的 buffer 中)觸發。在發起 asynchronous 讀寫請求時，需要傳入 userspace data buffer 的地址（用來存放結果資料），這樣 kernel thread 才可以自動幫我們把資料的讀寫工作完成，這裡的讀寫由作業系統來做，並不需要像 Reactor 那樣還需要主動發起 read/write 來讀寫資料，作業系統完成讀寫工作後，就會通知 application 直接處理資料。

## 為什麼目前有很多 Server 應用的是 Reactor Design Pattern，而不是 Proactor ? 
* 問題是 AIO 並不能完整應用在所有的作業系統
    * Windows 有比較完整的 AIO interface `IOCP`
    * MacOS 目前沒有相關介面
    * Linux 有一套 native async IO interface，但仍然有一些缺點，不過後來有出現 io_uring 這個介面，但是 io_uring 是 2019 年 Linux 5.1 才引入的


### Linux native async IO 缺點
1. 必須設定為 `O_DIRECT` 
    * Open 的時候通過 flag 來指定 `O_DIRECT` 參數，之後資料的 write/read 操作都是繞過 OS 維護的 page cache，直接對 disk 做 I/O 操作，但不支援對於 network sockets 的 I/O 操作
    * 普遍情況下，這樣的設定會影響效能
2. Linux AIO 雖然是 Asynchronous 的，但可能會 block

## TODO: io_uring

## Reference
* https://www.zhihu.com/question/26943938
* https://arthurchiao.art/blog/intro-to-io-uring-zh/





