5種網絡通訊設計模型(也稱IO模型)

一、基本概念

同步:同步函數通常指調用函數後,等到函數功能實現再返回,期間一直霸佔的CPU,等待期間同一個線程沒法執行其餘函數數組

異步:異步函數指調用函數後,無論函數功能是否實現,立馬返回;經過回調函數等告知函數功能完成網絡

阻塞:調用某些函數阻塞是由於函數功能沒有實現,主動放棄CPU,讓其餘線程的得以執行;當功能實現後,函數返回數據結構

非阻塞:調用某些函數不會進入阻塞,不管實現與否,都會返回結果併發

 

二、5種 IO 模型

阻塞模型

應用程序調用一個IO函數,致使應用程序阻塞,等待數據準備好。 若是數據沒有準備好,一直等待框架

特色:

  當但願可以當即發送和接收數據,且處理的套接字數量比較少的狀況下,使用阻塞模式來開發網絡程序比較合適。異步

  阻塞模式套接字的不足表現爲,在大量創建好的套接字線程之間進行通訊時比較困難。當使用「生產者-消費者」模型開發網絡程序時,爲每一個套接字都分別分配一個讀線程、一個處理數據線程和一個用於同步的事件,那麼這樣無疑加大系統的開銷。其最大的缺點是當但願同時處理大量套接字時,將無從下手,其擴展性不好socket

 

非阻塞模型

程序框架以下:函數

while true {
    for i in stream[]
    {
        if i has data
        read until unavailable
    }
}

 

特色:

  不像阻塞模型須要爲每一個socket建立一個線程,非阻塞只須要一個線程,可是會一直佔用CPU性能

 

複用模型

      I/O複用模型會用到select、poll、epoll函數,這幾個函數也會使進程阻塞(根據實參規定最長進入阻塞時間,是否進入阻塞),可是和阻塞I/O所不一樣的的,這些函數能夠同時阻塞多個I/O操做。並且能夠同時對多個讀操做、多個寫操做的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操做函數。測試

epoll跟select都能提供多路I/O複用的解決方案。在如今的Linux內核裏有都可以支持,其中epoll是Linux所特有,而select則應該是POSIX所規定,通常操做系統均有實現

 

select:

程序框架以下:

while true {
    select(streams[])
    for i in streams[] {
        if i has data
            read until unavailable
    }
}

 

select本質上是經過設置或者檢查存放fd標誌位的數據結構來進行下一步處理。這樣所帶來的缺點是:

一、 單個進程可監視的fd數量被限制,即能監聽端口的大小有限。

      通常來講這個數目和系統內存關係很大,具體數目能夠cat /proc/sys/fs/file-max察看。32位機默認是1024個。64位機默認是2048.

二、 對socket進行掃描時是線性掃描,即採用輪詢的方法,效率較低:

       由於select()只會告訴咱們有套接字可讀或可寫,沒有指明是哪一個套接字的哪一個事件發生,因此須要遍歷每一個套接字,時間複雜度是O(n)。若是能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操做,那就避免了輪詢,這正是epoll與kqueue作的。

三、須要維護一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時複製開銷大

poll:(有待從新組織語言)

poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,而後查詢每一個fd對應的設備狀態,若是設備就緒則在設備等待隊列中加入一項並繼續遍歷,若是遍歷完全部fd後沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒後它又要再次遍歷fd。這個過程經歷了屢次無謂的遍歷。

它沒有最大鏈接數的限制,緣由是它是基於鏈表來存儲的,可是一樣有一個缺點:

一、大量的fd的數組被總體複製於用戶態和內核地址空間之間,而無論這樣的複製是否是有意義。

二、poll還有一個特色是「水平觸發」,若是報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。

epoll:

程序框架以下;

while true {
    active_stream[] = epoll_wait(epollfd)
    for i in active_stream[] {
        read or write till unavailable
    }
}

 

epoll支持水平觸發和邊緣觸發,最大的特色在於邊緣觸發,它只告訴進程哪些fd剛剛變爲就需態,而且只會通知一次。還有一個特色是,epoll使用「事件」的就緒通知方式,經過epoll_ctl註冊fd,一旦該fd就緒,內核就會採用相似callback的回調機制來激活該fd,epoll_wait即可以收到通知

epoll的優勢:

一、相比於select,沒有最大併發鏈接的限制,能打開的FD的上限遠大於1024(1G的內存上能監聽約10萬個端口);
二、效率提高,不是無差異輪詢的方式,不會隨着FD數目的增長效率降低。只有活躍可用的FD纔會調用callback函數,時間複雜度爲O(k),k爲產生I/O事件的流的個數
      即Epoll最大的優勢就在於它只管你「活躍」的鏈接,而跟鏈接總數無關,所以在實際的網絡環境中,Epoll的效率就會遠遠高於select和poll。
三、 內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞;即epoll使用mmap減小複製開銷。

select、poll、epoll 區別總結:

 

一、一個進程所能打開的最大鏈接數

select

單個進程所能打開的最大鏈接數由FD_SETSIZE宏定義,其大小是32個整數的大小(在32位的機器上,大小就是32*32,同理64位機器上FD_SETSIZE爲32*64),固然咱們能夠對進行修改,而後從新編譯內核,可是性能可能會受到影響,這須要進一步的測試。

poll

poll本質上和select沒有區別,可是它沒有最大鏈接數的限制,緣由是它是基於鏈表來存儲的

epoll

雖然鏈接數有上限,可是很大,1G內存的機器上能夠打開10萬左右的鏈接,2G內存的機器能夠打開20萬左右的鏈接

二、FD劇增後帶來的IO效率問題

select

由於每次調用時都會對鏈接進行線性遍歷,因此隨着FD的增長會形成遍歷速度慢的「線性降低性能問題」。

poll

同上

epoll

由於epoll內核中實現是根據每一個fd上的callback函數來實現的,只有活躍的socket纔會主動調用callback,因此在活躍socket較少的狀況下,使用epoll沒有前面二者的線性降低的性能問題,可是全部socket都很活躍的狀況下,可能會有性能問題。

三、 消息傳遞方式

select

內核須要將消息傳遞到用戶空間,都須要內核拷貝動做

poll

同上

epoll

epoll經過內核和用戶空間共享一塊內存來實現的。

總結:

綜上,在選擇select,poll,epoll時要根據具體的使用場合以及這三種方式的自身特色。

一、表面上看epoll的性能最好,可是在鏈接數少而且鏈接都十分活躍的狀況下,select和poll的性能可能比epoll好,畢竟epoll的通知機制須要不少函數回調

二、select低效是由於每次它都須要輪詢。但低效也是相對的,視狀況而定,也可經過良好的設計改善

三、epoll 能顯著提升程序在大量併發鏈接中只有少許活躍的狀況下的系統CPU利用率

 

信號驅動模型

    首先咱們容許套接口進行信號驅動I/O,並安裝一個信號處理函數,進程繼續運行並不阻塞。當數據準備好時,進程會收到一個SIGIO信號,能夠在信號處理函數中調用I/O操做函數處理數據。

 

異步模型

  簡介:數據拷貝的時候進程無需阻塞。

     當一個異步過程調用發出後,調用者不能馬上獲得結果。實際處理這個調用的部件在完成後,經過狀態、通知和回調來通知調用者的輸入輸出操做

 

比較

相關文章
相關標籤/搜索