Windows五種IO模型性能分析和Linux五種IO模型性能分析

Windows五種IO模型性能分析和Linux五種IO模型性能分析

http://blog.csdn.net/jay900323/article/details/18141217html

http://blog.csdn.net/jay900323/article/details/18140847web

重疊I/O模型的另外幾個優勢在於,微軟針對重疊I/O模型提供了一些特有的擴展函數。當使用重疊I/O模型時,能夠選擇使用不一樣的完成通知方式。  ajax

採用事件對象通知的重疊I/O模型是不可伸縮的,由於針對發出WSAWaitForMultipleEvents調用的每一個線程,該I/O模型一次最多都只能支持6 4個套接字。假如想讓這個模型同時管理不止64個套接字,必須建立額外的工做者線程,以便等待更多的事件對象。由於操做系統同時可以處理的事件對象是有限的,因此基於事件對象的I/O模型不具有伸縮性。  使用完成例程通知的重疊I/O模型,由於如下幾個緣由,也不是開發高性能服務器的最佳選擇。首先,許多擴展功能不容許使用APC(Asyncroneus Procedure Call,異步過程調用)完成通知。其次,因爲APC在系統內部特有的處理機制,應用程序線程可能無限等待而得不到完成通知。當一個線程處於「可警告狀態」時,全部掛起的APC按照先進先出的順序(FIFO)接受處理。如今考慮這樣一種狀況,服務器已經創建起了一個鏈接,而且調用含有完成例程指針的WSARecv投遞了一個重疊I/O請求。當有數據到達時(即I/O完成時),完成例程執行而且再次調用WSARecv拋出另一個重疊I/O請求。一個APC拋出的I/O操做須要必定的時間才能完成,因此這期間可能另一個完成例程等待執行(好比本次WSARecv還沒接收完時,又有一個新的客戶接入併發來數據),由於還有更多的數據須要讀取(上一個客戶發來的數據還沒有讀完)。只要(投遞WSARecv的)那個套接字上還有「未決」(未接收完)的數據,就會致使調用線程長久阻塞。  基於完成端口通知的重疊I/O模型是Windows NT系統提供的一個真正支持高伸縮性的I/O模型。在上一章中,探討了Winsock幾種常見的I/O模型,而且說明了當應對大規模客戶鏈接時,完成端口是最佳的選擇,由於它提供了最好的伸縮性。  對不一樣Winsock I/O模型的性能測試結果如圖1所示。其中服務器採用Pentium 4 1.7 GHz Xeon的CPU,768M內存;客戶端有3臺PC,配置分別是Pentium 2 233MHz ,128 MB 內存,Pentium 2 350 MHz ,128 MB內存,Itanium 733 MHz ,1 GB內存。服務器、客戶端安裝的操做系統都是Windows XP。算法

image

圖1 不一樣I/O模型的性能比較  數據庫

1.分析圖表1提供的測試結果可知,在所用的I/O模型中,阻塞模式性能最差。這個測試程序中,服務器爲每一個客戶建立兩個線程:一個負責處理數據的接收,一個負責處理數據的發送。在屢次測試中的共同問題就是,阻塞模式難以應對大規模的客戶鏈接,由於它在建立線程上耗費了太多的系統資源。所以,服務器建立太多的線程後,再調用CreateThread函數時,將返回ERROR_NOT_ENOUGH_MEMORY的錯誤,這個錯誤碼提示內存不夠。那些發出鏈接請求的客戶則收到WSAECONNREFUSED的錯誤提示,表示鏈接的嘗試被拒絕。  讓咱們來看看監聽函數listen,其原型以下:  WINSOCK_API_LINKAGE int WSAAPI listen(SOCKET s, int backlog );  參數一s已綁定了地址的監聽套接字。  參數二backlog指定了正在等待鏈接的最大隊列長度。  參數backdog很是重要, 由於徹底可能同時出現幾個對服務器的鏈接請求。例如,假定backlog參數爲2時有三個客戶機同時發出鏈接請求,那麼前兩個會被放在一個「等待處理」隊列中,以便應用程序依次爲它們提供服務。而第三個鏈接的請求就會形成一個WSAECONNREFUSED錯誤。一旦服務器接受了一個鏈接請求,那個鏈接請求就會從隊列中刪去,以即可以繼續接收其餘客戶發出的鏈接請求。即當一個鏈接請求到來時隊列已滿,那麼客戶將收到一個WSAECONNREFUSED錯誤。而backlog參數自己的大小就存在着限制,這個限制是由協議提供者決定的。  故阻塞模式下,因爲系統資源的限制,其併發處理量是極難突破的。 編程

2.非阻塞模式表現出的性能要比阻塞模式稍好,可是佔用了太多的CPU處理時間。測試服務器將全部客戶對應的socket分類放到FD_SET集合中,而後調用select函數篩選出對應集合中有事件發生的socket,並對集合更新。接下來調用FD_ISSET宏從新判斷一個套接字是否在原來加入的FD_SET集合中。隨着客戶鏈接數量的增多,這種模型的侷限性逐漸凸現。僅僅爲了判斷一個套接字是否有網絡事件發生,就須要對集合FD_SET執行一次遍歷!使用迭代搜索來對select更新的FD_SET進行掃描,性能能夠獲得一些提高。瓶頸在於,服務器必須可以很快地掃描出FD_SET集合中的有網絡事件發生的套接字的相關信息。針對這個問題,可使用更復雜的掃描算法,如哈希搜索,它的效率是極高的。還須要注意的一個問題就是,非分頁池(即直接在物理內存中分配的內存)的使用極高。這是由於AFD(Ancillary Function Driver,由afd.sys提供的支持Windows Sockets應用程序的底層驅動程序,其中運行在內核模式下afd.sys驅動程序主要管理Winsock TCP/IP通訊)和TCP都將使用I/O緩存,由於服務器讀取數據的速度是有限的,相對於CPU的處理速度而言,I/O基本是零字節的吞吐量。 數組

3.基於Windows消息機制的WSAAsyncSelect模型可以處理必定的客戶鏈接量,可是擴展性也不是很好。由於消息泵很快就會阻塞,下降了消息處理的速度。在幾回測試中,服務器只能處理大約1/3的客戶端鏈接。過多的客戶端鏈接請求都將返回錯誤提示碼WSAECONNREFUSED,說明服務器不能及時處理FD_ACCEPT消息致使鏈接失敗,這樣監聽隊列中待處理的鏈接請求不致於爆滿。然而,經過上表中的數據能夠發現,對那些已經創建的鏈接,其平均吞吐量也是極低的(即便對於那些對比特率進行了限制的客戶也如此)。 瀏覽器

4.基於事件通知的WSAEventSelect模型表現得出奇的不錯。在全部的測試中,大多數時候,服務器基本可以處理全部的客戶鏈接,而且保持着較高的數據吞吐量。這種模型的缺點是,每當有一個新鏈接時,須要動態管理線程池,由於每一個線程只可以等待64個事件對象。當客戶鏈接量超過64個後再有新客戶接入時,須要建立新的線程。在最後一次測試中,創建起了超過45,000個的客戶鏈接後,系統響應速度變得很是緩慢。這時因爲爲處理大規模的客戶鏈接建立了大量的線程,佔用了過多的系統資源。791個線程基本達到了極限,服務器不能再接受更多的鏈接了,緣由是WSAENOBUFS:無可用的緩衝區空間,套接字沒法建立。另外,客戶端程序也達到了極限,不能維持已經創建的鏈接。  使用事件通知的重疊I/O模型和WSAEventSelect模型在伸縮性上差很少。這兩種模型都依賴於等待事件通知的線程池,處理客戶通訊時,大量線程上下文的切換是它們共同的制約因素。重疊I/O模型和WSAEventSelect模型的測試結果很類似,都表現得不錯,直到線程數量超過極限。 緩存

5.最後是針對基於完成端口通知的重疊I/O模型的性能測試,由上表中數據能夠看出,它是全部I/O模型中性能最佳的。內存使用率(包括用戶分頁池和非分頁池)和支持的客戶鏈接量與基於事件通知的重疊I/O模型和WSAEventSelect模型基本相同。真正不一樣的地方,在於對CPU的佔用。完成端口模型只佔用了60%的CPU,可是在維持一樣規模的鏈接量時,另外兩種模型(基於事件通知的重疊I/O模型和WSAEventSelect模型)佔用更多的CPU。完成端口的另一個明顯的優點是,它維持更大的吞吐量。  對以上各類模型進行分析後,能夠會發現客戶端與服務器數據通訊機制自己存在的缺陷是一個瓶頸。在以上測試中,服務器被設計成只作簡單的迴應,即只是將客戶端發送過來的數據發送回去。客戶端(即便有比特率限制)不停的發送數據給服務器,這致使大量數據阻塞在服務器上與這個客戶端對應的套接字上(不管是TCP緩衝區仍是AFD的單套接字緩衝區,它們都是在非分頁池上)。在最後三種性能比較好的模型中,同一時間只能執行一個接受輸入操做,這意味着在大多數時間,仍是有不少數據處於「未決」狀態。能夠修改服務器程序使其以異步方式接受數據,這樣一旦有數據達到,須要將數據緩存起來。這種方案的缺點是,當一個客戶連續發送數據時,異步接受到了大量的數據。這會致使其餘的客戶沒法接入,由於調用線程和工做者線程都不能處理其餘的事件或完成通知。一般狀況下,調用非阻塞異步接收函數,先返回WSAEWOULDBLOCK,而後數據間斷性的傳輸,而不採起連續接收的方式。  從以上測試結果,能夠看出WSAEventSelect模型和重疊I/O模型是性能表現最佳的。兩種基於事件通知的模型中,建立線程池來等待事件完成通知並做後續處理是很繁瑣的,可是並不影響以它們來架構中型服務器的良好性能。當線程的數量隨着客戶端鏈接數量而逐增時,CPU將花費大量時間在線程的上下文切換上,這將影響服務器的伸縮性,由於鏈接量達到必定數量後,便飽和了。完成端口模型提供了最佳的可擴展性,由於CPU使用率低,其支持的客戶鏈接量相對其餘模型最多。  I/O模型的選擇  經過上一節對各類模型的測試分析,對於如何挑選最適合本身應用程序的I/O模型已經很明晰了。同開發一個簡單的運行多線程的鎖定模式應用相比,其餘每種I/O模型都須要更爲複雜的編程工做。所以,針對客戶機和服務器應用開發模型的選擇,有如下原則。  1. 客戶端  若打算開發一個客戶機應用,令其同時管理一個或多個套接字,那麼建議採用重疊I/O或WSAEventSelect模型,以便在必定程度上提高性能。然而,假如開發的是一個以Windows爲基礎的應用程序,要進行窗口消息的管理,那麼WSAAsyncSelect模型恐怕是一種最好的選擇,由於WSAAsyncSelect自己即是從Windows消息模型借鑑來的。採用這種模型,程序需具有消息處理功能。  2. 服務器端  若開發的是一個服務器應用,要在一個給定的時間,同時控制多個套接字,建議採用重疊I/O模型,這一樣是從性能角度考慮的。可是,若是服務器在任何給定的時間,都會爲大量I/O請求提供服務,便應考慮使用I/O完成端口模型,從而得到更佳的性能。安全

 


 

socket阻塞與非阻塞,同步與異步

 

做者:huangguisu

 

 

 

 

1. 概念理解

 

 

 

     在進行網絡編程時,咱們經常見到同步(Sync)/異步(Async),阻塞(Block)/非阻塞(Unblock)四種調用方式:
同步:
      所謂同步,就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不返回。也就是必須一件一件事作,等前一件作完了才能作下一件事。

 

 

 

例如普通B/S模式(同步):提交請求->等待服務器處理->處理完畢返回 這個期間客戶端瀏覽器不能幹任何事

 

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

 

     例如 ajax請求(異步): 請求經過事件觸發->服務器處理(這是瀏覽器仍然能夠做其餘事情)->處理完畢

 

阻塞
     阻塞調用是指調用結果返回以前,當前線程會被掛起(線程進入非可執行狀態,在這個狀態下,cpu不會給線程分配時間片,即線程暫停運行)。函數只有在獲得結果以後纔會返回。

 

     有人也許會把阻塞調用和同步調用等同起來,實際上他是不一樣的。對於同步調用來講,不少時候當前線程仍是激活的,只是從邏輯上當前函數沒有返回而已。 例如,咱們在socket中調用recv函數,若是緩衝區中沒有數據,這個函數就會一直等待,直到有數據才返回。而此時,當前線程還會繼續處理各類各樣的消息。

 

非阻塞
      非阻塞和阻塞的概念相對應,指在不能馬上獲得結果以前,該函數不會阻塞當前線程,而會馬上返回。
對象的阻塞模式和阻塞函數調用
對象是否處於阻塞模式和函數是否是阻塞調用有很強的相關性,可是並非一一對應的。阻塞對象上能夠有非阻塞的調用方式,咱們能夠經過必定的API去輪詢狀 態,在適當的時候調用阻塞函數,就能夠避免阻塞。而對於非阻塞對象,調用特殊的函數也能夠進入阻塞調用。函數select就是這樣的一個例子。

 

 

 

1. 同步,就是我調用一個功能,該功能沒有結束前,我死等結果。
2. 異步,就是我調用一個功能,不須要知道該功能結果,該功能有結果後通知我(回調通知)
3. 阻塞,      就是調用我(函數),我(函數)沒有接收完數據或者沒有獲得結果以前,我不會返回。
4. 非阻塞,  就是調用我(函數),我(函數)當即返回,經過select通知調用者

 

 

 

同步IO和異步IO的區別就在於:數據拷貝的時候進程是否阻塞!

 

阻塞IO和非阻塞IO的區別就在於:應用程序的調用是否當即返回!


對於舉個簡單c/s 模式:

 

 

 

同步:提交請求->等待服務器處理->處理完畢返回這個期間客戶端瀏覽器不能幹任何事 異步:請求經過事件觸發->服務器處理(這是瀏覽器仍然能夠做其餘事情)->處理完畢

 

同步和異步都只針對於本機SOCKET而言的。

 

同步和異步,阻塞和非阻塞,有些混用,其實它們徹底不是一回事,並且它們修飾的對象也不相同。 阻塞和非阻塞是指當進程訪問的數據若是還沒有就緒,進程是否須要等待,簡單說這至關於函數內部的實現區別,也就是未就緒時是直接返回仍是等待就緒;

而同步和異步是指訪問數據的機制,同步通常指主動請求並等待I/O操做完畢的方式,當數據就緒後在讀寫的時候必須阻塞(區別就緒與讀寫二個階段,同步的讀寫必須阻塞),異步則指主動請求數據後即可以繼續處理其它任務,隨後等待I/O,操做完畢的通知,這可使進程在數據讀寫時也不阻塞。(等待"通知")

 

 

1. Linux下的五種I/O模型

 

1)阻塞I/O(blocking I/O) 2)非阻塞I/O (nonblocking I/O) 3) I/O複用(select 和poll) (I/O multiplexing) 4)信號驅動I/O (signal driven I/O (SIGIO)) 5)異步I/O (asynchronous I/O (the POSIX aio_functions))

 

前四種都是同步,只有最後一種纔是異步IO。

阻塞I/O模型:

        簡介:進程會一直阻塞,直到數據拷貝完成

     應用程序調用一個IO函數,致使應用程序阻塞,等待數據準備好。 若是數據沒有準備好,一直等待….數據準備好了,從內核拷貝到用戶空間,IO函數返回成功指示。

阻塞I/O模型圖:在調用recv()/recvfrom()函數時,發生在內核中等待數據和複製數據的過程。

    當調用recv()函數時,系統首先查是否有準備好的數據。若是數據沒有準備好,那麼系統就處於等待狀態。當數據準備好後,將數據從系統緩衝區複製到用戶空間,而後該函數返回。在套接應用程序中,當調用recv()函數時,未必用戶空間就已經存在數據,那麼此時recv()函數就會處於等待狀態。

 

     當使用socket()函數和WSASocket()函數建立套接字時,默認的套接字都是阻塞的。這意味着當調用Windows Sockets API不能當即完成時,線程處於等待狀態,直到操做完成。

    並非全部Windows Sockets API以阻塞套接字爲參數調用都會發生阻塞。例如,以阻塞模式的套接字爲參數調用bind()、listen()函數時,函數會當即返回。將可能阻塞套接字的Windows Sockets API調用分爲如下四種:

    1.輸入操做: recv()、recvfrom()、WSARecv()和WSARecvfrom()函數。以阻塞套接字爲參數調用該函數接收數據。若是此時套接字緩衝區內沒有數據可讀,則調用線程在數據到來前一直睡眠。

    2.輸出操做: send()、sendto()、WSASend()和WSASendto()函數。以阻塞套接字爲參數調用該函數發送數據。若是套接字緩衝區沒有可用空間,線程會一直睡眠,直到有空間。

    3.接受鏈接:accept()和WSAAcept()函數。以阻塞套接字爲參數調用該函數,等待接受對方的鏈接請求。若是此時沒有鏈接請求,線程就會進入睡眠狀態。

   4.外出鏈接:connect()和WSAConnect()函數。對於TCP鏈接,客戶端以阻塞套接字爲參數,調用該函數向服務器發起鏈接。該函數在收到服務器的應答前,不會返回。這意味着TCP鏈接總會等待至少到服務器的一次往返時間。

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

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

非阻塞IO模型 

 

 

 

       簡介:非阻塞IO經過進程反覆調用IO函數(屢次系統調用,並立刻返回);在數據拷貝的過程當中,進程是阻塞的;

 

 

 

       

 

       咱們把一個SOCKET接口設置爲非阻塞就是告訴內核,當所請求的I/O操做沒法完成時,不要將進程睡眠,而是返回一個錯誤。這樣咱們的I/O操做函數將不斷的測試數據是否已經準備好,若是沒有準備好,繼續測試,直到數據準備好爲止。在這個不斷測試的過程當中,會大量的佔用CPU的時間。

 

    把SOCKET設置爲非阻塞模式,即通知系統內核:在調用Windows Sockets API時,不要讓線程睡眠,而應該讓函數當即返回。在返回時,該函數返回一個錯誤代碼。圖所示,一個非阻塞模式套接字屢次調用recv()函數的過程。前三次調用recv()函數時,內核數據尚未準備好。所以,該函數當即返回WSAEWOULDBLOCK錯誤代碼。第四次調用recv()函數時,數據已經準備好,被複制到應用程序的緩衝區中,recv()函數返回成功指示,應用程序開始處理數據。

 

 

     當使用socket()函數和WSASocket()函數建立套接字時,默認都是阻塞的。在建立套接字以後,經過調用ioctlsocket()函數,將該套接字設置爲非阻塞模式。Linux下的函數是:fcntl().
    套接字設置爲非阻塞模式後,在調用Windows Sockets API函數時,調用函數會當即返回。大多數狀況下,這些函數調用都會調用「失敗」,並返回WSAEWOULDBLOCK錯誤代碼。說明請求的操做在調用期間內沒有時間完成。一般,應用程序須要重複調用該函數,直到得到成功返回代碼。

 

    須要說明的是並不是全部的Windows Sockets API在非阻塞模式下調用,都會返回WSAEWOULDBLOCK錯誤。例如,以非阻塞模式的套接字爲參數調用bind()函數時,就不會返回該錯誤代碼。固然,在調用WSAStartup()函數時更不會返回該錯誤代碼,由於該函數是應用程序第一調用的函數,固然不會返回這樣的錯誤代碼。

 

    要將套接字設置爲非阻塞模式,除了使用ioctlsocket()函數以外,還可使用WSAAsyncselect()和WSAEventselect()函數。當調用該函數時,套接字會自動地設置爲非阻塞方式。

 

  因爲使用非阻塞套接字在調用函數時,會常常返回WSAEWOULDBLOCK錯誤。因此在任什麼時候候,都應仔細檢查返回代碼並做好對「失敗」的準備。應用程序接二連三地調用這個函數,直到它返回成功指示爲止。上面的程序清單中,在While循環體內不斷地調用recv()函數,以讀入1024個字節的數據。這種作法很浪費系統資源。

 

    要完成這樣的操做,有人使用MSG_PEEK標誌調用recv()函數查看緩衝區中是否有數據可讀。一樣,這種方法也很差。由於該作法對系統形成的開銷是很大的,而且應用程序至少要調用recv()函數兩次,才能實際地讀入數據。較好的作法是,使用套接字的「I/O模型」來判斷非阻塞套接字是否可讀可寫。

 

    非阻塞模式套接字與阻塞模式套接字相比,不容易使用。使用非阻塞模式套接字,須要編寫更多的代碼,以便在每一個Windows Sockets API函數調用中,對收到的WSAEWOULDBLOCK錯誤進行處理。所以,非阻塞套接字便顯得有些難於使用。

 

    可是,非阻塞套接字在控制創建的多個鏈接,在數據的收發量不均,時間不定時,明顯具備優點。這種套接字在使用上存在必定難度,但只要排除了這些困難,它在功能上仍是很是強大的。一般狀況下,可考慮使用套接字的「I/O模型」,它有助於應用程序經過異步方式,同時對一個或多個套接字的通訊加以管理。

 

IO複用模型:

 

             簡介:主要是select和epoll;對一個IO端口,兩次調用,兩次返回,比阻塞IO並無什麼優越性;關鍵是能實現同時對多個IO端口進行監聽;

 

      I/O複用模型會用到select、poll、epoll函數,這幾個函數也會使進程阻塞,可是和阻塞I/O所不一樣的的,這兩個函數能夠同時阻塞多個I/O操做。並且能夠同時對多個讀操做,多個寫操做的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操做函數。

 

 

信號驅動IO

 

 

 

    簡介:兩次調用,兩次返回;

 

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

 

 

異步IO模型

 

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

 

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

同步IO引發進程阻塞,直至IO操做完成。 異步IO不會引發進程阻塞。 IO複用是先經過select調用阻塞。

 

 

 

5個I/O模型的比較:

 

 

 

 

 

 

 

1. select、poll、epoll簡介

 

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

 

 

 

select:

 

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

 

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

 

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

 

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

 

       當套接字比較多的時候,每次select()都要經過遍歷FD_SETSIZE個Socket來完成調度,無論哪一個Socket是活躍的,都遍歷一遍。這會浪費不少CPU時間。若是能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操做,那就避免了輪詢,這正是epoll與kqueue作的。

 

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

 

poll:

 

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

 

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

 

一、大量的fd的數組被總體複製於用戶態和內核地址空間之間,而無論這樣的複製是否是有意義。                                                                                                                                      二、poll還有一個特色是「水平觸發」,若是報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。

epoll:

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

 

epoll的優勢:

 

 

 

一、沒有最大併發鏈接的限制,能打開的FD的上限遠大於1024(1G的內存上能監聽約10萬個端口); 二、效率提高,不是輪詢的方式,不會隨着FD數目的增長效率降低。只有活躍可用的FD纔會調用callback函數;       即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低效是由於每次它都須要輪詢。但低效也是相對的,視狀況而定,也可經過良好的設計改善

 




https://www.cnblogs.com/lixinjie/p/a-post-tell-clearly-about-io-multiplexing-and-async-io.html


真正的多路複用技術
多路複用技術本來指的是,在通訊方面,多種信號或數據(從宏觀上看)交織在一塊兒,使用同一條傳輸通道進行傳輸。
這樣作的目的,一方面能夠充分利用通道的傳輸能力,另外一方面天然是省時省力省錢啦。
其實這個概念很是的「生活化」,隨手就能夠舉個例子:
一條小水渠裏水在流,在一端往裏倒入大量乒乓球,在另外一端用網進行過濾,把乒乓球和水流分開。
這就是一個比較「土」的多路複用,首先在發射端把多種信號或數據進行「混合」,接着是在通道上進行傳輸,最後在接收端「分離」出本身須要的信號或數據。
相信你們都看出來了,這裏的重點其實就是處理好「混合」和「分離」,對於不一樣的信號或數據,有不一樣的處理方法。
好比之前的有線電視是模擬信號,即電磁波。一家通常只有一根信號線,但能夠同時接多個電視,每一個電視任意換臺,互不影響。
這是因爲不一樣頻率的波能夠混合和分離。(固然,可能不是十分準確,明白意思就好了。)
再好比城市的高鐵站通常都有數個站臺供高鐵(同時)停靠,但城市間的高鐵軌道單方向只有一條,如何保證那麼多趟高鐵安全運行呢?
很明顯是分時使用,每趟高鐵都有本身的時刻。多趟高鐵按不一樣的時刻出站至關於混合,按不一樣的時刻進站至關於分離。
總結一下,多路指的是多種不一樣的信號或數據或其它事物,複用指的是共用同一個物理鏈路或通道或載體。
可見,多路複用技術是一種一對多的模型,「多」的這一方複用了「一」的這一方。
其實,一對多的模型主要體如今「公用」上或「共享」上。



這種處理模式就是被稱爲的多路複用I/O,多路指的是多個Socket通道,複用指的是隻用一個線程來管理它們。



就飯店而言,究竟幾張桌子配一個跑腿服務員,幾張桌子配一個點餐服務員,通過一段時間運行,必定會有一個最優解。
就程序而言,究竟須要幾個選擇器線程,幾個工做線程,通過評估測試後,也會有一個最優解。
一旦達到最優解後,就不可能再提高了,這一樣是由多路複用這種一對多的形式所限制的。就像一對一的形式限制同樣。
人們的追求是無止境的,如何對多路複用繼續提高呢?答案必定是具備顛覆性的,即拋棄多路複用,採用全新的形式。
還以飯店爲例,如何在最優解的狀況下,既要繼續減小服務員數量,還要使效率提高呢?可能有些朋友已經猜到了,那就是拋棄服務員服務客人這種模式,把飯店改爲自助餐廳。



對比與結論:
處理一樣的20個請求,一個須要用20個線程,一個須要用6個線程,一個須要3個線程,又節省了50%線程數。
BIO是阻塞IO,能夠是同步阻塞,也能夠是異步阻塞。AIO是異步IO,只有異步非阻塞這一種。所以沒有同步非阻塞這種說法,由於同步必定是阻塞的。





分配一個讀線程、一個處理數據線程和一個用於同步的事件



一個數據庫socket線程 -》同時對多個硬盤發過來的IO端口數據

簡介:主要是select和epoll;對一個IO端口,兩次調用,兩次返回,比阻塞IO並無什麼優越性;關鍵是能實現同時對多個IO端口進行監聽;異步IO多路複用

相關文章
相關標籤/搜索