背景知識
關于同步/異步,阻塞/非阻塞的解釋除了參見《Unix網絡編程》之外,知乎中,“愚蠢”和“大姚”分別進行了通俗和詳盡的解釋。
參考:https://www.zhihu.com/question/19732473
阻塞式的結構性能一定是低下的,這里主要比較同步非阻塞式和異步非阻塞式結構,也就是Reactor和Proactor這兩個結構。
參考:http://www.artima.com/articles/io_design_patterns.html
正文
Reactor:多路分用器等待事件告知讀寫準備就緒,將事件分發給合適的Handler,Handler真正負責讀寫工作(這里就是同步的地方)。
Proactor:IO的讀寫操作是由OS完成的。Handler將用戶定義好的緩沖區作為參數傳給OS,等待OS完成讀寫操作后,由事件的多路分用器通知Handler。
Reactor中的Handler關注(Ready to Read)事件,Handler負責讀寫。
Proactor中的Handler關注(Receiving Completion)事件,OS負責讀寫。
為什么不能向上層程序員提供統一的接口,讓程序員不關心其內部實現到底是Reactor還是Proactor呢?
由于Proactor結構需要OS Async API的支持,但并不是所有的OS都提供健壯的API。所以很難設計出統一的外部接口,所以也就很難設計出可移植的框架來封裝與操作系統有關的操作。不過文中也提到了一種簡單的方法來解決這個問題,具體見Page 2/3.
理論上Proactor模式具有最好的擴展性和性能,但Nginx選擇了Reactor,其原因如下:
Proactor邏輯實現復雜,并且Proactor需要操作系統的異步API支持,而Linux主要還是通過Epoll和Select來進行事件驅動。對異步API支持比較好的是Windows IOCP。
Kitura在OSX下使用了dispatch_io,在Linux下使用了Epoll。其原因是Epoll在Linux下性能較低,原因不明。
參考:https://github.com/IBM-Swift/Kitura/issues/121
Reference
https://segmentfault.com/a/1190000002715832