同步和异步, 阻塞和非阻塞, Reactor和Proactor
http://www.artima.com/articles/io_design_patterns.html
http://note.sdo.com/u/1434409594/n/lvRFW~kjR2N0LX0nE004_r
http://www.cnblogs.com/xuxm2007/archive/2011/08/15/2139808.html, 圖示
?
我看了些blog, 很少有人能說清楚的, 而且很多人的理解根本就不對
通俗的說
阻塞和非阻塞, 等不等的問題, 傻等就是阻塞, 不等就是非阻塞?
異步和同步, 是否有并發的問題, 同步只是改變順序, 現在這個不ready, 先做別的去, 等ready再回來做. 而異步, 我只告訴你干啥然后我干別的去了, 你把事干完后再通知我.(這里的并發不是應用層的多線程并發, 而是只應用層和系統層之間的并發)
再舉個簡單的例子, 去銀行辦手續, 人很多?
最不濟的方法, 排隊等, 這就是阻塞的方式?
如果選擇不等就是非阻塞的方式,?
a, 輪詢, 每隔段時間來看看人多不, 不多就辦, 人多就去干其他的事, 仍然很麻煩需要不斷輪詢?
b, 通知方式(同步方式), 在銀行有熟人, 讓他在人少的時候打電話通知你, 這就比較高效, 等人少的時候再去辦理, 有效節省了等待和輪詢的時間?
c, VIP方式(異步方式), 到銀行直接說我要取多少錢或什么業務, 辦好后把錢放在我的保險柜里, 并通知我, 然后該干嗎干嗎去了.?
?? 這個方式最高效, 因為存在并發, 你在做其他事情的時候, 銀行的手續也同時辦了?
通過這個例子可以看出來, 效率越高的方法需要的代價也越大, 沒有免費的午餐...?
阻塞和非阻塞輪詢, 在效率上沒有太大的分別, 甚至阻塞可能效率更高些. 這個可以通過日常的生活證明, 很多人都會選擇排隊等, 而不是過會再來. 所以他們的代價也是基本一樣的, 你一個人就可以搞定, 不需要其他人幫助, 在程序中就是只需要client進程就ok
非阻塞的同步方式, 需要有人通知你, 在程序中, 除了client進程, 還需要event demultiplexor進程(負責通知event)
非阻塞的異步方式, 不但需要人通知你, 還需要銀行幫你處理業務(前提是銀行提供這種服務), 你還需要提供保險箱用來存放辦理好的業務和錢. 所以在程序中, 就比較復雜, 需要client進程, 需要event demultiplexor進程(負責通知event), 需要操作系統進程(前提是操作系統支持異步I/O), 還需要分配數據緩存區(保存結果)
再來解釋Reactor和Proactor就很容易了, Reactor是非阻塞的同步方式, 而Proactor是非阻塞的異步方式
所以說, 哪種方法更好, 看你的場景, 從復雜度, 程序效率, 耗費, 和OS的支持等方面考慮
?
TProactor方案, 使用Reactor模擬異步
前面說Proactor雖然好, 但問題在于依賴OS的支持, 比如Unix對于這個的支持就不好, 所以無法使用, 但是又想用異步的方式, 怎么辦??
上面的文章提出一種方案, TProactor, 用Reactor來模擬Proactor
具體做法也很簡單, 還是銀行的例子, 國有銀行比較牛比, 不提供代辦服務?
沒事, 我讓負責通知我的人來替代銀行來幫我辦理, 然后再通知我?
在程序中, 就是讓event demultiplexor完成數據讀取, 存放到自定義的緩沖區, 并通知client.?
從程序角度說
blocking I/O
阻塞的方式, 進程從調用recvfrom系統調用開始, 一直阻塞, 從wait for data, copy data from kernel to user, 到最終返回
?
?
nonblocking I/O, 輪詢
?
I/O multiplexing (select, poll,?epoll, kqueue)
這應該是現在最常用的方式, 因為Unix對異步I/O不支持, 所以Reactor設計模式是現在的主流模式?
需要兩次系統調用, 先使用select返回ready的socket, 然后調用recvfrom讀數據?
調用select本身是阻塞的, 但select可以同時監控多個I/O, 所以可以理解成是一種非阻塞的方式(不在一個I/O上阻塞)?
select作為event demultiplexor發送數據ready的通知
select, poll, epoll, kqueue的區別?
select為最基礎的版本, 其他都是select的升級版本, 但本質都是一樣的?
select, 每次都要通過遍歷FD_SETSIZE個Socket來check哪些有數據, 所以當監控的socket比較多的時候, 非常低效?
poll, select()受限于FD_SETSIZE個句柄, 而poll沒有這個限制, 但是仍然是輪詢所有socket, 這種方式被稱為'level triggered'
epoll, kqueue是基于socket的callback的, 所以避免輪詢, 當socket狀態發生變化時會自動event通知, 缺點是event只會在狀態變化時發送一次, 后面如果狀態不變化, 就不會發送任何event, 所以如果發生event丟失會比較麻煩. 這種方式稱為'edge triggered'?(Jonathon Lemon introduced the terms in his?BSDCON 2000 paper on kqueue())
?
signal driven I/O (SIGIO)
只有UNIX系統支持, 通過注冊signal和handler, 數據ready時利用系統signal進行通知, 仍是同步方式
?
asynchronous I/O (the POSIX aio_functions)
純粹的異步方式, 但好像只有windows的IOCP有比較好的支持
?
Comparation
可見從左往右, 越來越先進, 至到完全異步, 但是前面也說相應的實現代價也是越來越大……
?
?
http://www.kegel.com/c10k.html,?The C10K problem翻譯
http://en.wikipedia.org/wiki/C10k_problem
http://wenku.baidu.com/view/33e41da6f524ccbff12184f9.html
本文章摘自博客園,原文發布日期:2013-05-25
總結
以上是生活随笔為你收集整理的同步和异步, 阻塞和非阻塞, Reactor和Proactor的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读矢泽久雄三本书总结
- 下一篇: 脑洞大开的 iPhone 配件,看看你有