天天看點

伺服器程式設計模型

【注】:本篇側重基本概念了解,不涉及代碼實作細節

同步與異步

同步

同步是指程式在執行一次調用時,在沒有得到結果之前,程式不會傳回,一旦程式傳回了,也就得到了傳回結果。
           

異步

異步是指程式在發出調用時,不等調用結果傳回就會立即傳回,異步通常結合回調實作。(異步往往意味着非阻塞)
           

總結

同步是自己等結果,異步是别人通知你
           

阻塞與非阻塞

阻塞

阻塞是指在程式不能立即得到傳回結果時(一個時間片以内)目前線程會被挂起。
           

非阻塞

非阻塞是指在程式調用不能立即得到傳回結果時,目前線程不會被挂起。
           

總結

阻塞程式讓出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模型的實作細節(更側重代碼實作)。