【注】:本篇側重基本概念了解,不涉及代碼實作細節
同步與異步
同步
同步是指程式在執行一次調用時,在沒有得到結果之前,程式不會傳回,一旦程式傳回了,也就得到了傳回結果。
異步
異步是指程式在發出調用時,不等調用結果傳回就會立即傳回,異步通常結合回調實作。(異步往往意味着非阻塞)
總結
同步是自己等結果,異步是别人通知你
阻塞與非阻塞
阻塞
阻塞是指在程式不能立即得到傳回結果時(一個時間片以内)目前線程會被挂起。
非阻塞
非阻塞是指在程式調用不能立即得到傳回結果時,目前線程不會被挂起。
總結
阻塞程式讓出CPU被挂起,非阻塞程式還會繼續占用CPU
阻塞與非阻塞 同步與異步的關系
同步阻塞
常見的IO操作,IO阻塞,程式被挂起,在沒有得到結果之前之前不會傳回。
同步非阻塞
正常編寫的程式不涉及到大量耗時的操作都是同步非阻塞
異步阻塞
讓程式異步,就是為了為了讓其非阻塞,目前還未見過異步阻塞的程式
異步非阻塞
異步非阻塞模型常見的有兩種。一種是以node.js為代表的單線程事件+回調的模型,另外一種是以python語言為代表的協程方式。利用協程實作的異步非阻塞本身也是基于事件+回調的模型,隻不過此時回調函數利用協程實作後,各個協程可以獨自管理自己的狀态,避免了大量回調帶來的回調地獄
常用的五種伺服器模型
同步阻塞模型
- 最古老的伺服器程式設計模型,效率低下,程式一旦遇到耗時IO便會被阻塞挂起
- 單程序單線程
多程序模型
- 多程序模型支援多道程式的并發執行,伺服器的并發能力相比同步阻塞模型大大提高
- 說的并發對單核CPU而言,隻是宏觀上并行,在微觀上仍然是串行
- 對于單個程序而言仍然是同步阻塞
- 程序是系統進行資源配置設定的最小機關,系統配置設定資源需要從使用者态切換到核心态,這是一個耗時的過程,是以對于高并發的場景,基于多程序的伺服器并扛不住。
多線程模型
- 線程是CPU進行排程的最小機關
- 多個線程共享程序資源
- 線程切換相比程序切換資源開銷要小很多
- 對于單個線程而言仍然是同步阻塞的。
- 多線程模型不好的方面是遇到臨界資源處理時需要鎖機制,加鎖會大大降低伺服器的并發性能
注:上面三種模型均是同步阻塞的模型
IO多路複用(select/poll)
- IO多路複用的本質就是在單程序内将原來阻塞的IO的操作改為事件+回調的模式,向作業系統注冊感興趣的事件,當有事件發生時作業系統會傳回發生事件的句柄,然後觸發對應回調函數即可。
- select模型是早期Linux支援的IO多路複用模型,效率低下,select的最大檔案描述符隻支援1024個
- select傳回整個檔案句柄的數組,隻有周遊數組才能發現哪些句柄發生了事件
epoll模型
- epoll模型是目前Linux支援IO多路複用最高效的模型,它是select模型的增強版
- 相比select模型,epoll模型消除了最大檔案描述符不再有限制,也就意味着最多可以支援65535個
- epoll隻傳回有事件發生的句柄
- epoll模型的缺點是仍然沒有解決異步+回調中的回調地獄問題
上面基本上把常用的五種IO模型給介紹完了,可以看到當伺服器模型發展到今天,唯一困擾的問題就是異步IO中的無限回調帶來的回調地獄和回調棧撕裂問題,于是目前很多語言開始支援協程,協程是比線程更小的執行單元,不同于程序線程,協程對于作業系統是透明的,它的切換可以由程式員自己顯示指定,基于協程解決了回調函數之間的資源傳遞問題,各個協程獨立管理自己的資源。epoll+Coroutine的模型就是Python中高性能web架構Tornado的實作原理。回頭會專門整理一篇Tornado模型的實作細節(更側重代碼實作)。