<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          搞懂I/O多路復(fù)用及其技術(shù)

          共 4400字,需瀏覽 9分鐘

           ·

          2020-12-28 08:25

          點(diǎn)擊上方「藍(lán)字」關(guān)注我們

          前言

          高性能是每個(gè)程序員的追求,無(wú)論寫一行代碼還是做一個(gè)系統(tǒng),都希望能夠達(dá)到高性能的效果。高性能架構(gòu)設(shè)計(jì)主要集中在兩方面:

          • 盡量提升單服務(wù)器的性能,將單服務(wù)器的性能發(fā)揮到極致

          • 如果單服務(wù)器無(wú)法支撐性能,設(shè)計(jì)服務(wù)器集群方案

          單服務(wù)器高性能的關(guān)鍵之一就是服務(wù)器采取的網(wǎng)絡(luò)編程模型。服務(wù)器如何管理連接,如何處理請(qǐng)求等。這兩個(gè)設(shè)計(jì)點(diǎn)最終都和操作系統(tǒng)的I/O模型及進(jìn)程模型相關(guān)。

          • I/O模型:阻塞、非阻塞、同步、異步

          • 進(jìn)程模型:?jiǎn)芜M(jìn)程、多進(jìn)程、多線程。

          我們所說(shuō)的I/O模型是指網(wǎng)絡(luò)I/O模型,就是服務(wù)端如何管理連接,如何請(qǐng)求連接的措施,是用一個(gè)進(jìn)程管理一個(gè)連接(PPC),還是一個(gè)線程管理一個(gè)連接(TPC),亦或者一個(gè)進(jìn)程管理多個(gè)連接(Reactor)。

          因此IO多路復(fù)用中多路就是多個(gè)TCP連接(或多個(gè)Channel),復(fù)用就是指復(fù)用一個(gè)或少量線程,理解起來(lái)就是多個(gè)網(wǎng)路IO復(fù)用一個(gè)或少量線程來(lái)處理這些連接。

          常見(jiàn)I/O模型

          • 同步阻塞IO(Blocking IO):即傳統(tǒng)IO模型

          • 同步非阻塞IO(Non-blocking IO):默認(rèn)常見(jiàn)的socket都是阻塞的,非阻塞IO要求socket被設(shè)置成NONBLOCK

          • IO多路復(fù)用(IO Multiplexing):即經(jīng)典的Reactor設(shè)計(jì)模式,也被稱為異步阻塞IO,Java中的selector和linux中的epoll都是這種模型

          • 異步IO(Asychronous IO):即Proactor設(shè)計(jì)模式,也被稱為異步非阻塞IO

          同步和異步的概念描述的是用戶線程與內(nèi)核的交互方式,這里所說(shuō)的用戶進(jìn)程/線程和內(nèi)核是以傳輸層為分割線的,傳輸層以上是指用戶進(jìn)程,傳輸層以下(包括傳輸層)是指內(nèi)核(處理所有通信細(xì)節(jié),發(fā)送數(shù)據(jù),等待確認(rèn),給無(wú)序到達(dá)的數(shù)據(jù)排序等,這四層是操作系統(tǒng)內(nèi)核的一部分)。同步是指用戶線程發(fā)起IO請(qǐng)求后需要等待或者輪詢內(nèi)核IO操作,完成后才能繼續(xù)執(zhí)行。異步是指用戶線程發(fā)起IO請(qǐng)求后仍繼續(xù)執(zhí)行,當(dāng)內(nèi)核IO操作完成后回通知用戶線程,或者調(diào)用用戶線程注冊(cè)的回調(diào)函數(shù)。

          阻塞和非阻塞的概念描述的是用戶線程調(diào)用內(nèi)核IO操作的方式,阻塞時(shí)指IO操作需要徹底完成后才能返回用戶空間,非阻塞時(shí)指IO操作被調(diào)用后立即返回給用戶一個(gè)狀態(tài)值,無(wú)需等待IO操作徹底完成。

          同步阻塞IO

          同步阻塞IO是最簡(jiǎn)單的IO模型,用戶線程在內(nèi)核進(jìn)行IO操作時(shí)被阻塞。用戶線程通過(guò)調(diào)用系統(tǒng)調(diào)用read發(fā)起IO讀操作,由用戶空間轉(zhuǎn)到內(nèi)核空間。內(nèi)核等到數(shù)據(jù)包到達(dá)后,然后將接受的數(shù)據(jù)拷貝到用戶空間,完成read操作。整個(gè)IO請(qǐng)求過(guò)程,用戶線程都是被阻塞的,對(duì)CPU利用率不夠

          同步非阻塞IO

          在同步基礎(chǔ)上,將socket設(shè)置為NONBLOCK,這樣用戶線程可以在發(fā)起IO請(qǐng)求后立即返回。雖說(shuō)可以立即返回,但并未讀到任何數(shù)據(jù),用戶線程需要不斷的發(fā)起IO請(qǐng)求,直到數(shù)據(jù)到達(dá)后才能真正讀到數(shù)據(jù),然后去處理。

          整個(gè)IO請(qǐng)求中,雖然可以立即返回,但是因?yàn)槭峭降模瑸榱说鹊綌?shù)據(jù),需要不斷的輪詢、重復(fù)請(qǐng)求,消耗了大量的CPU資源。因此,這種模型很少使用,實(shí)際用處不大。

          IO多路復(fù)用

          不管是同步阻塞還是同步非阻塞,對(duì)系統(tǒng)性能的提升都是很小的。而通過(guò)復(fù)用可以使一個(gè)或一組線程(線程池)處理多個(gè)TCP連接。IO多路復(fù)用使用兩個(gè)系統(tǒng)調(diào)用(select/poll/epoll和recvfrom),blocking IO只調(diào)用了recvfrom。select/poll/epoll核心是可以同時(shí)處理多個(gè)connection,而不是更快,所以連接數(shù)不高的話,性能不一定比多線程+阻塞IO好。

          select是內(nèi)核提供的多路分離函數(shù),使用它可以避免同步非阻塞IO中輪詢等待問(wèn)題。

          用戶首先將需要進(jìn)行IO操作的socket添加到select中,然后阻塞等待select系統(tǒng)調(diào)用返回。當(dāng)數(shù)據(jù)到達(dá)時(shí),socket被激活,select函數(shù)返回,用戶線程正式發(fā)起read請(qǐng)求,讀取數(shù)據(jù)并繼續(xù)執(zhí)行。

          這么一看,這種方式和同步阻塞IO并沒(méi)有太大區(qū)別,甚至還多了添加監(jiān)視socket以及調(diào)用select函數(shù)的額外操作,效率更差。但是使用select以后,用戶可以在一個(gè)線程內(nèi)同時(shí)處理多個(gè)socket的IO請(qǐng)求,這就是它的最大優(yōu)勢(shì)。用戶可以注冊(cè)多個(gè)socket,然后不斷調(diào)用select讀取被激活的socket,即可達(dá)到同一個(gè)線程同時(shí)處理多個(gè)IO請(qǐng)求的目的。而在同步阻塞模型中,必須通過(guò)多線程方式才能達(dá)到這個(gè)目的。所以IO多路復(fù)用設(shè)計(jì)目的其實(shí)不是為了快,而是為了解決線程/進(jìn)程數(shù)量過(guò)多對(duì)服務(wù)器開銷造成的壓力。

          select(socket);?#向select注冊(cè)socket
          while(true){
          ????????sockets?=?select();?#獲取被激活的socket
          ????????for(socket?in?sockets){
          ????????????????if(can_read(socket)){???#socket可讀,調(diào)用read讀取數(shù)據(jù)
          ????????????????????????read(socket,buffer);
          ????????????????????????process(buffer);
          ????????????????}
          ????????}
          }

          雖然這種方式允許單線程內(nèi)處理多個(gè)IO請(qǐng)求,但是每個(gè)IO請(qǐng)求的過(guò)程還是阻塞的(在select函數(shù)上阻塞),平均時(shí)間甚至比同步阻塞IO模型還要長(zhǎng)。如果用戶線程只注冊(cè)自己感興趣的socket,然后去做自己的事情,等到數(shù)據(jù)到來(lái)時(shí)在進(jìn)行處理,則可以提高CPU利用率。

          通過(guò)Reactor方式,用戶線程輪詢IO操作狀態(tài)的工作統(tǒng)一交給handle_events事件循環(huán)處理。用戶線程注冊(cè)事件處理器之后可以繼續(xù)執(zhí)行做其他的工作(異步),而Reactor線程負(fù)責(zé)調(diào)用內(nèi)核的select函數(shù)檢查socket狀態(tài)。當(dāng)有socket被激活時(shí),則通知相應(yīng)的用戶線程(或執(zhí)行用戶線程的回調(diào)函數(shù)),執(zhí)行handel_envent進(jìn)行數(shù)據(jù)的讀取、處理工作。

          由于select函數(shù)是阻塞的,因此多路IO復(fù)用模型就被稱為異步阻塞IO模型,這里阻塞不是指socket。因?yàn)槭褂肐O多路復(fù)用時(shí),socket都設(shè)置NONBLOCK,不過(guò)不影響,因?yàn)橛脩舭l(fā)起IO請(qǐng)求時(shí),數(shù)據(jù)已經(jīng)到達(dá)了,用戶線程一定不會(huì)被阻塞。

          IO多路復(fù)用是最常用的IO模型,但其異步程度還不徹底,因?yàn)樗褂昧嘶刈枞€程的select系統(tǒng)調(diào)用。因此IO多路復(fù)用只能稱為異步阻塞IO,而非真正的異步IO。

          附:Reactor設(shè)計(jì)模式

          異步非阻塞IO

          在IO多路復(fù)用模型中,事件循環(huán)文件句柄的狀態(tài)事件通知給用戶線程,由用戶線程自行讀取數(shù)據(jù)、處理數(shù)據(jù)。而異步IO中,當(dāng)用戶線程收到通知時(shí)候,數(shù)據(jù)已經(jīng)被內(nèi)核讀取完畢,并放在了用戶線程指定的緩沖區(qū)內(nèi),內(nèi)核在IO完成后通知用戶線程直接使用就行了。因此這種模型需要操作系統(tǒng)更強(qiáng)的支持,把read操作從用戶線程轉(zhuǎn)移到了內(nèi)核。

          相比于IO多路復(fù)用模型,異步IO并不十分常用,不少高性能并發(fā)服務(wù)程序使用IO多路復(fù)用+多線程任務(wù)處理的架構(gòu)基本可以滿足需求。不過(guò)最主要原因還是操作系統(tǒng)對(duì)異步IO的支持并非特別完善,更多的采用IO多路復(fù)用模擬異步IO方式(IO事件觸發(fā)時(shí)不直接通知用戶線程,而是將數(shù)據(jù)讀寫完畢后放到用戶指定的緩沖區(qū))。

          select、poll、epoll詳解

          select,poll,epoll都是IO多路復(fù)用的機(jī)制。I/O多路復(fù)用就是通過(guò)一種機(jī)制,一個(gè)進(jìn)程可以監(jiān)視多個(gè)描述符(socket),一旦某個(gè)描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進(jìn)行相應(yīng)的讀寫操作。雖說(shuō)IO多路復(fù)用被稱為異步阻塞IO,但select,poll,epoll本質(zhì)上都是同步IO,因?yàn)樗鼈兌夹枰诶m(xù)寫事件就緒后自己負(fù)責(zé)進(jìn)行讀寫,也就是說(shuō)這個(gè)讀寫過(guò)程是阻塞的,而真正意義上的異步IO無(wú)需自己負(fù)責(zé)進(jìn)行讀寫。

          select

          int?select(int?n,?fd_set?*readfds,?fd_set?*writefds,
          ?fd_set?*exceptfds,?struct?timeval?*timeout);

          select函數(shù)監(jiān)視的文件描述符有三類,readfds,writefds,exceptfds。調(diào)用后函數(shù)會(huì)阻塞,直到有描述符就緒(有數(shù)據(jù)讀、寫、或者有except),或者超時(shí)(timeout指定時(shí)間,如果立即返回設(shè)置null),函數(shù)返回。當(dāng)select函數(shù)返回后,可以通過(guò)便利fdset,來(lái)找到就緒的描述符。

          優(yōu)點(diǎn):良好的跨平臺(tái)性。

          缺點(diǎn):?jiǎn)蝹€(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,在Linux上為1024,可以通過(guò)修改宏定義甚至重新編譯內(nèi)核的方式提升這一限制,但這樣會(huì)造成效率的降低。

          poll

          int?poll(struct?poll?*fds,?unsigned?int?nfds,?int?timeout);
          struct?pollfd{
          ??int?fd;
          ??short?events;
          ??short?revents;
          };

          與select使用三個(gè)位圖來(lái)表示fdset,poll使用一個(gè)pollfd的指針實(shí)現(xiàn)。pollfd結(jié)構(gòu)包含了要監(jiān)視的event和發(fā)生的event,不在使用select參數(shù)傳值的方式。同時(shí)pollfd并沒(méi)有最大數(shù)量的限制(但數(shù)量過(guò)大性能也會(huì)下降)。和select一樣,poll返回后,需要輪詢pollfd來(lái)或許就緒的描述符。

          epoll

          epoll是select和poll的增強(qiáng)版本,相比于前兩者,它更加的靈活,沒(méi)有描述符的限制。epoll使用一個(gè)文件描述符管理多個(gè)描述符,將用戶關(guān)系的文件描述符的事件存放到內(nèi)核的一個(gè)事件表中,這樣在用戶空間和內(nèi)核空間的copy只需要一次。

          參考鏈接:
          https://blog.csdn.net/sehanlingfeng/article/details/78920423
          https://www.cnblogs.com/wlwl/p/10293057.html
          https://www.cnblogs.com/natian-ws/p/10785649.html
          https://segmentfault.com/a/1190000003063859
          《架構(gòu)修煉之道》《從零開始學(xué)架構(gòu)》

          source:https://www.cnblogs.com/yrxing/p/14143644.html

          掃碼二維碼

          獲取更多精彩

          Java樂(lè)園

          有用!分享+在看?
          瀏覽 71
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚州乱伦网| 高清无码高潮 | 91人妻网站 | 操老熟女| 婷婷色基地|