---
# System prepended metadata

title: Reactor vs Proactor
tags: [Research]

---

---
tags: Research 
---
# Reactor vs Proactor
## Difference
* 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，而 Linux 有提供一套 native async IO interface，不過這套介面存在一些缺點。首先，在開啟檔案時必須設定為 `O_DIRECT`，之後資料的 write/read 操作都是繞過 OS 維護的 page cache，直接對 disk 做 I/O 操作，但這套 AIO 不支援對於 network sockets 的 I/O 操作，而且普遍情況下，這樣的設定會影響效能。第二個缺點是 Linux AIO 雖然是 Asynchronous 的，但卻有很多原因會使 io_submit 出現 block 現象。不過後來在 Liunx 系統上實作了 io_uring 介面，但 io_uring 是 2019 年 Linux 5.1 才引入的。 另外， MacOS 並沒有提供 async IO interface。 因此目前大部分 Server 應用的是 Reactor Design Pattern
  
## Proactor 缺點
1. 系統分常複雜
    * 需要 handler 去區分 request 是 I/O 操作還是連線操作
    * 連線操作會有 acceptor
    * I/O 操作會直接進行 Asynchronous I/O 交由 OS 去做
    * OS 做完會把完成的任務放到 queue 裡面，Proactor 會持續去看 event queue 是否有完成的事件，有的話則交由 completion handler
    * completion handler 去做 I/O 完成後要處理的事
2. Asynchronous 操作難以 debug，很難得知程式執行的順序
3. request 有相依或是有順序性時，必須實作讓 asynchonous 有 priority 或是可以取消，那這部分在複雜系統很難實作 

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