<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] 轉載:https://www.cnblogs.com/guxuanqing/p/12416130.html 參考: https://cloud.tencent.com/developer/article/1681177 ## 什么是IO多路復用 * IO多路復用是一種同步IO模型,實現一個線程可以監視多個文件句柄;一旦某個文件句柄就緒,就能夠通知應用程序進行相應的讀寫操作;沒有文件句柄就緒時會阻塞應用程序,交出cpu。**多路是指網絡連接,復用指的是同一個線程**,意思是一個線程處理多個網絡連接的IO ## 為什么需要IO多路復用 沒有IO多路復用機制時,有同步阻塞IO(BIO)、同步非阻塞IO(NIO)兩種實現方式 ### 同步阻塞(BIO) * 服務端采用單線程,當accept一個請求后,在recv或send調用阻塞時,將無法accept其他請求(必須等上一個請求處recv或send完),這種模式下`無法處理并發` * 服務器端采用多線程,當accept一個請求后,開啟線程進行recv,可以完成并發處理,但隨著請求數增加需要增加系統線程, >`大量的線程占用很大的內存空間,并且線程切換會帶來很大的開銷,10000個線程真正發生讀寫事件的線程數不會超過20%,每次accept都開一個線程也是一種資源浪費` ### 同步非阻塞(NIO) * 服務器端當accept一個請求后,加入fds集合,每次輪詢一遍fds集合recv(非阻塞)數據,沒有數據則立即返回錯誤, >`每次輪詢所有fd(包括沒有發生讀寫事件的fd)會很浪費cpu` ### **IO多路復用(現在的做法)** * 服務器端采用單線程通過select/epoll等系統調用獲取fd列表,遍歷有事件的fd進行accept/recv/send,使其能`支持更多的并發連接請求` * select/epoll 是同步非阻塞的 ## IO多路復用的幾種實現方式 ### **select** #### select的優缺點 select的優點:可以在一個線程上同時監聽多個連接請求。 select的幾大缺點: * 每次調用select,都需要把fd集合(文件描述符)從用戶態拷貝到內核態,這個開銷在fd很多時會很大 * 同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大 * select支持的文件描述符數量太小了,默認是1024 ### **poll** poll的實現和select非常相似,只是描述fd集合的方式不同,poll使用pollfd結構而不是select的fd\_set結構,poll支持的文件描述符數量沒有限制,其他的都差不多。 poll缺點: * 每次調用poll,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大 * 對socket掃描時是線性掃描,采用輪詢的方法,效率較低(高并發時) ### **epoll**  epoll是對select和poll的改進,能避免上述的三個缺點,select和poll都只提供了一個函數——select或者poll函數。而epoll提供了三個函數,epoll\_create,epoll\_ctl和epoll\_wait,epoll\_create是創建一個epoll句柄;epoll\_ctl是注冊要監聽的事件類型;epoll\_wait則是等待事件的產生。 >epoll只能工作在linux下 **epoll LT 與 ET模式的區別** * epoll有EPOLLLT和EPOLLET兩種觸發模式,LT是默認的模式,ET是“高速”模式。 * 1. 水平觸發的主要特點是,如果用戶在監聽epoll事件,當內核有事件的時候,會拷貝給用戶態事件,但是如果用戶只處理了一次,那么剩下沒有處理的會在下一次epoll_wait再次返回該事件。 * 2. 邊緣觸發,相對跟水平觸發相反,當內核有事件到達, 只會通知用戶一次,至于用戶處理還是不處理,以后將不會再通知---**直到下次再有數據流入之前都不會再提示了**。這樣減少了拷貝過程,增加了性能,但是相對來說,如果用戶馬虎忘記處理,將會產生事件丟的情況。 ` ` #### 解決select第一個缺點   對于第一個缺點,epoll的解決方案在epoll\_ctl函數中。**每次注冊新的事件到epoll句柄中時(在epoll\_ctl中指定EPOLL\_CTL\_ADD),會把所有的fd拷貝進內核,而不是在epoll\_wait的時候重復拷貝。epoll保證了每個fd在整個過程中只會拷貝一次。** ` ` #### 解決select第二個缺點   對于第二個缺點,epoll的解決方案不像select或poll一樣每次都把current(當前描述符)輪流加入fd對應的設備等待隊列中,而只在epoll\_ctl時把current掛一遍(這一遍必不可少)并為每個fd指定一個回調函數,當設備就緒,喚醒等待隊列上的等待者時,就會調用這個回調函數,而這個回調函數會把就緒的fd加入一個就緒鏈表)。epoll\_wait的工作實際上就是在這個就緒鏈表中查看有沒有就緒的fd(利用schedule\_timeout()實現睡一會,判斷一會的效果,和select中的實現是類似的)。 ` ` #### 解決select第三個缺點   對于第三個缺點,epoll沒有這個限制,它所支持的FD上限是最大可以打開文件的數目,這個數字一般遠大于2048,舉個例子,在1GB內存的機器上大約是10萬左右,具體數目在linux上可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統內存關系很大。 ` ` select,poll實現需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用epoll\_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調用回調函數,把就緒fd放入就緒鏈表中,并喚醒在epoll\_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為空就行了,這節省了大量的CPU時間。這就是回調機制帶來的性能提升。 ` ` select,poll每次調用都要把fd集合從用戶態往內核態拷貝一次,并且要把current往設備等待隊列中掛一次,而epoll只要一次拷貝,而且把current往等待隊列上掛也只掛一次(在epoll\_wait的開始,注意這里的等待隊列并不是設備等待隊列,只是一個epoll內部定義的等待隊列)。這也能節省不少的開銷。 #### 總結epoll ? ? ? ? epoll屬于IO多路復用,它只是模擬實現了異步IO的功能。? “真正”的異步IO需要操作系統更強的支持。在IO多路復用模型中,事件循環將文件句柄的狀態事件通知給用戶線程,由用戶線程自行讀取數據、處理數據。而在異步IO模型中,當用戶線程收到通知時,數據已經被內核讀取完畢,并放在了用戶線程指定的緩沖區內,內核在IO完成后通知用戶線程直接使用即可。 ` ` ### epoll和poll觸發時的區別 ? epoll 因為采用 mmap的機制, 使得 內核socket buffer和 用戶空間的 buffer共享, 從而省去了 socket data copy, 這也意味著, 當epoll 回調上層的 callback函數來處理 socket 數據時, 數據已經從內核層 "自動" 到了用戶空間, 雖然和 用poll 一樣, 用戶層的代碼還必須要調用 read/write, 但這個函數內部實現所觸發的深度不同了。 ` ` ? ? ? ?用poll時, poll通知用戶空間的Appliation時, 數據還在內核空間, 所以Appliation調用 read API 時, 內部會做 copy socket data from kenel space to user space。 ` ` ? ? ? ?而用 epoll 時, epoll 通知用戶空間的Appliation時,?數據已經在用戶空間, 所以?Appliation調用 read API 時,?只是讀取用戶空間的 buffer, 沒有 kernal space和 user space的switch了。 ### IOCP(異步io----iocp,epoll) ? ? ? ? ? IOCP全稱 IO完成端口。它是一種WIN32的網絡I/O模型,既包括了網絡連接部分,也負責了部分的I/O操作功能,用于方便我們控制有并發性的網絡I/O操作。它有如下特點: 1:它是一個WIN32內核對象,所以無法運行于linux。 2:它自己負責維護了工作線程池,同時也負責了I/O通道的內存池。 3:它自己實現了線程的管理以及I/O請求通知,最小化的做到了線程的上下文切換。 4:它自己實現了線程的優化調度,提高了CPU和內存緩沖的使用率。 >**真正意義上的異步IO嚴格的來說只有IOCP,但是epoll也模擬實現了異步IO的功能。** ? ? ? ### IOCP和Epoll之間的異同。 異: 1:IOCP是WINDOWS系統下使用。Epoll是Linux系統下使用。 2:IOCP是IO操作完畢之后,通過Get函數獲得一個完成的事件通知。 Epoll是當你希望進行一個IO操作時,向Epoll查詢是否可讀或者可寫,若處于可讀或可寫狀態后,Epoll會通過epoll\_wait進行通知。 3:IOCP封裝了異步的消息事件的通知機制,同時封裝了部分IO操作。但Epoll僅僅封裝了一個異步事件的通知機制,并不負責IO讀寫操作,但是因為mmap機制,epoll其實已經省去了IO操作的第二部分(將數據從內核緩沖區復制到進程緩沖區)。 4: 基于上面的描述,我們可以知道Epoll不負責IO操作,所以它只告訴你當前可讀可寫了,并且將協議讀寫緩沖填充,由用戶去讀寫控制,此時我們可以做出額 外的許多操作。IOCP則直接將IO通道里的讀寫操作都做完了才通知用戶,當IO通道里發生了堵塞等狀況我們是無法控制的。 同: 1:它們都是異步的事件驅動的網絡模型。 2:它們都可以向底層進行指針數據傳遞,當返回事件時,除可通知事件類型外,還可以通知事件相關數據(通知到來時IO已經完全完成)。 ## 總結 ### select/poll/epoll之間的區別 | | select | poll | epoll | | --- | --- | --- | --- | | 數據結構 | bitmap | 數組 | 紅黑樹 | |最大連接數 | 1024 | 無上限(最大可以打開文件的數目) | 無上限(最大可以打開文件的數目)| | fd拷貝 | 每次調用select拷貝 | 每次調用poll拷貝 | fd首次調用epoll\_ctl拷貝,每次調用epoll\_wait不拷貝 | | 工作效率 | 輪詢:O(n) | 輪詢:O(n) | 回調:O(1) | ### **高頻面試題** * 什么是IO多路復用? * nginx/redis 所使用的IO模型是什么? * select、poll、epoll之間的區別 * epoll 水平觸發(LT)與 邊緣觸發(ET)的區別?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看