欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    對于我一個(gè)python初學(xué)者來說,今天花了3個(gè)小時(shí)左右的時(shí)間完整搞定了圖形驗(yàn)證碼的識(shí)別功能,并且可以正常登錄成功。

    "MSG":"SUCCESS",

    作者:jaydenwen,騰訊 pcg 后臺(tái)開發(fā)工程師

    在互聯(lián)網(wǎng)中提起網(wǎng)絡(luò),我們都會(huì)避免不了討論高并發(fā)、百萬連接。而此處的百萬連接的實(shí)現(xiàn),脫離不了網(wǎng)絡(luò) IO 的選擇,因此本文作為一篇個(gè)人學(xué)習(xí)的筆記,特此進(jìn)行記錄一下整個(gè)網(wǎng)絡(luò) IO 的發(fā)展演變過程。以及目前廣泛使用的網(wǎng)絡(luò)模型。

    1.網(wǎng)絡(luò) IO 的發(fā)展

    在本節(jié)內(nèi)容中,我們將一步一步介紹網(wǎng)絡(luò) IO 的演變發(fā)展過程。介紹完發(fā)展過程后,再對網(wǎng)絡(luò) IO 中幾組容易混淆的概念進(jìn)行對比、分析。

    1.1 網(wǎng)絡(luò) IO 的各個(gè)發(fā)展階段

    通常,我們在此討論的網(wǎng)絡(luò) IO 一般都是針對 linux 操作系統(tǒng)而言。網(wǎng)絡(luò) IO 的發(fā)展過程是隨著 linux 的內(nèi)核演變而變化,因此網(wǎng)絡(luò) IO 大致可以分為如下幾個(gè)階段:

    1. 阻塞 IO(BIO)
    2. 非阻塞 IO(NIO)
    3. IO 多路復(fù)用第一版(select/poll)
    4. IO 多路復(fù)用第二版(epoll)
    5. 異步 IO(AIO)

    而每一個(gè)階段,都是因?yàn)楫?dāng)前的網(wǎng)絡(luò)有一些缺陷,因此又在不斷改進(jìn)該缺陷。這是網(wǎng)絡(luò) IO 一直演變過程中的本質(zhì)。下面將對上述幾個(gè)階段進(jìn)行介紹,并對每個(gè)階段的網(wǎng)絡(luò) IO 解決了哪些問題、優(yōu)點(diǎn)、缺點(diǎn)進(jìn)行剖析。

    1.2 網(wǎng)絡(luò)的兩個(gè)階段

    在網(wǎng)絡(luò)中,我們通常可以將其廣義上劃分為以下兩個(gè)階段:

    第一階段:硬件接口到內(nèi)核態(tài)
    第二階段:內(nèi)核態(tài)到用戶態(tài)

    本人理解:我們通常上網(wǎng),大部分?jǐn)?shù)據(jù)都是通過網(wǎng)線傳遞的。因此對于兩臺(tái)計(jì)算機(jī)而言,要進(jìn)行網(wǎng)絡(luò)通信,其數(shù)據(jù)都是先從應(yīng)用程序傳遞到傳輸層(TCP/UDP)到達(dá)內(nèi)核態(tài),然后再到網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層、物理層,接著數(shù)據(jù)傳遞到硬件網(wǎng)卡,最后通過網(wǎng)絡(luò)傳輸介質(zhì)傳遞到對端機(jī)器的網(wǎng)卡,然后再一步一步數(shù)據(jù)從網(wǎng)卡傳遞到內(nèi)核態(tài),最后再拷貝到用戶態(tài)。

    1.3 阻塞 IO 和非阻塞 IO 的區(qū)別

    根據(jù) 1.2 節(jié)的內(nèi)容,我們可以知道,網(wǎng)絡(luò)中的數(shù)據(jù)傳輸從網(wǎng)絡(luò)傳輸介質(zhì)到達(dá)目的機(jī)器,需要如上兩個(gè)階段。此處我們把從硬件到內(nèi)核態(tài)這一階段,是否發(fā)生阻塞等待,可以將網(wǎng)絡(luò)分為阻塞 IO非阻塞 IO。如果用戶發(fā)起了讀寫請求,但內(nèi)核態(tài)數(shù)據(jù)還未準(zhǔn)備就緒,該階段不會(huì)阻塞用戶操作,內(nèi)核立馬返回,則稱為非阻塞 IO。如果該階段一直阻塞用戶操作。直到內(nèi)核態(tài)數(shù)據(jù)準(zhǔn)備就緒,才返回。這種方式稱為阻塞 IO。

    因此,區(qū)分阻塞 IO 和非阻塞 IO 主要看第一階段是否阻塞用戶操作。

    1.4 同步 IO 和異步 IO 的區(qū)別

    從前面我們知道了,數(shù)據(jù)的傳遞需要兩個(gè)階段,在此處只要任何一個(gè)階段會(huì)阻塞用戶請求,都將其稱為同步 IO,兩個(gè)階段都不阻塞,則稱為異步 IO。

    在目前所有的操作系統(tǒng)中,linux 中的 epoll、mac 的 kqueue 都屬于同步 IO,因?yàn)槠湓诘诙A段(數(shù)據(jù)從內(nèi)核態(tài)到用戶態(tài))都會(huì)發(fā)生拷貝阻塞。而只有 windows 中的 IOCP 才真正屬于異步 IO,即 AIO。

    2.阻塞 IO

    在本節(jié),我們將介紹最初的阻塞 IO,阻塞 IO 英文為 blocking IO,又稱為 BIO。根據(jù)前面的介紹,阻塞 IO 主要指的是第一階段(硬件網(wǎng)卡到內(nèi)核態(tài))。

    2.1 阻塞 IO 的概念

    阻塞 IO,顧名思義當(dāng)用戶發(fā)生了系統(tǒng)調(diào)用后,如果數(shù)據(jù)未從網(wǎng)卡到達(dá)內(nèi)核態(tài),內(nèi)核態(tài)數(shù)據(jù)未準(zhǔn)備好,此時(shí)會(huì)一直阻塞。直到數(shù)據(jù)就緒,然后從內(nèi)核態(tài)拷貝到用戶態(tài)再返回。具體過程可以參考 2.2 的圖示。

    2.2 阻塞 IO 的過程

    2.3 阻塞 IO 的缺點(diǎn)

    在一般使用阻塞 IO 時(shí),都需要配置多線程來使用,最常見的模型是阻塞 IO+多線程,每個(gè)連接一個(gè)單獨(dú)的線程進(jìn)行處理。

    我們知道,一般一個(gè)程序可以開辟的線程是有限的,而且開辟線程的開銷也是比較大的。也正是這種方式,會(huì)導(dǎo)致一個(gè)應(yīng)用程序可以處理的客戶端請求受限。面對百萬連接的情況,是無法處理。

    既然發(fā)現(xiàn)了問題,分析了問題,那就得解決問題。既然阻塞 IO 有問題,本質(zhì)是由于其阻塞導(dǎo)致的,因此自然而然引出了下面即將介紹的主角:非阻塞 IO

    3.非阻塞 IO

    非阻塞 IO 是為了解決前面提到的阻塞 IO 的缺陷而引出的,下面我們將介紹非阻塞 IO 的過程。

    3.1 非阻塞 IO 的概念

    非阻塞 IO:見名知意,就是在第一階段(網(wǎng)卡-內(nèi)核態(tài))數(shù)據(jù)未到達(dá)時(shí)不等待,然后直接返回。因此非阻塞 IO 需要不斷的用戶發(fā)起請求,詢問內(nèi)核數(shù)據(jù)好了沒,好了沒。

    3.2 非阻塞 IO 的過程

    非阻塞 IO 是需要系統(tǒng)內(nèi)核支持的,在創(chuàng)建了連接后,可以調(diào)用 setsockop 設(shè)置 noblocking

    3.3 非阻塞 IO 的優(yōu)點(diǎn)

    正如前面提到的,非阻塞 IO 解決了阻塞 IO每個(gè)連接一個(gè)線程處理的問題,所以其最大的優(yōu)點(diǎn)就是 一個(gè)線程可以處理多個(gè)連接,這也是其非阻塞決定的。

    3.4 非阻塞 IO 的缺點(diǎn)

    但這種模式,也有一個(gè)問題,就是需要用戶多次發(fā)起系統(tǒng)調(diào)用。頻繁的系統(tǒng)調(diào)用是比較消耗系統(tǒng)資源的。

    因此,既然存在這樣的問題,那么自然而然我們就需要解決該問題:保留非阻塞 IO 的優(yōu)點(diǎn)的前提下,減少系統(tǒng)調(diào)用

    4.IO 多路復(fù)用第一版

    為了解決非阻塞 IO 存在的頻繁的系統(tǒng)調(diào)用這個(gè)問題,隨著內(nèi)核的發(fā)展,出現(xiàn)了 IO 多路復(fù)用模型。那么我們就需要搞懂幾個(gè)問題:

    1. IO 多路復(fù)用到底復(fù)用什么?
    2. IO 多路復(fù)用如何復(fù)用?

    IO 多路復(fù)用: 很多人都說,IO 多路復(fù)用是用一個(gè)線程來管理多個(gè)網(wǎng)絡(luò)連接,但本人不太認(rèn)可,因?yàn)樵诜亲枞?IO 時(shí),就已經(jīng)可以實(shí)現(xiàn)一個(gè)線程處理多個(gè)網(wǎng)絡(luò)連接了,這個(gè)是由于其非阻塞而決定的。

    在此處,個(gè)人觀點(diǎn),多路復(fù)用主要復(fù)用的是通過有限次的系統(tǒng)調(diào)用來實(shí)現(xiàn)管理多個(gè)網(wǎng)絡(luò)連接。最簡單來說,我目前有 10 個(gè)連接,我可以通過一次系統(tǒng)調(diào)用將這 10 個(gè)連接都丟給內(nèi)核,讓內(nèi)核告訴我,哪些連接上面數(shù)據(jù)準(zhǔn)備好了,然后我再去讀取每個(gè)就緒的連接上的數(shù)據(jù)。因此,IO 多路復(fù)用,復(fù)用的是系統(tǒng)調(diào)用。通過有限次系統(tǒng)調(diào)用判斷海量連接是否數(shù)據(jù)準(zhǔn)備好了

    無論下面的 select、poll、epoll,其都是這種思想實(shí)現(xiàn)的,不過在實(shí)現(xiàn)上,select/poll 可以看做是第一版,而 epoll 是第二版

    4.1IO 多路復(fù)用第一版的概念

    IO 多路復(fù)用第一版,這個(gè)概念是本人想出來的,主要是方便將 select/poll 和 epoll 進(jìn)行區(qū)分

    所以此處 IO 多路復(fù)用第一版,主要特指 select 和 poll 這兩個(gè)。

    select 的 api

    // readfds:關(guān)心讀的fd集合;writefds:關(guān)心寫的fd集合;excepttfds:異常的fd集合
    int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    
    

    select 函數(shù)監(jiān)視的文件描述符分 3 類,分別是 writefds、readfds、和 exceptfds。調(diào)用后 select 函數(shù)會(huì)阻塞,直到有描述副就緒(有數(shù)據(jù) 可讀、可寫、或者有 except),或者超時(shí)(timeout 指定等待時(shí)間,如果立即返回設(shè)為 null 即可),函數(shù)返回。當(dāng) select 函數(shù)返回后,可以 通過遍歷 fdset,來找到就緒的描述符。

    select 目前幾乎在所有的平臺(tái)上支持,其良好跨平臺(tái)支持也是它的一個(gè)優(yōu)點(diǎn)。select 的一 個(gè)缺點(diǎn)在于單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,在 Linux 上一般為 1024,可以通過修改宏定義甚至重新編譯內(nèi)核的方式提升這一限制,但 是這樣也會(huì)造成效率的降低。

    poll 的 api

    int poll (struct pollfd *fds, unsigned int nfds, int timeout);
    
    struct pollfd {
        int fd; /* file descriptor */
        short events; /* requested events to watch */
        short revents; /* returned events witnessed */
    };
    
    

    pollfd 結(jié)構(gòu)包含了要監(jiān)視的 event 和發(fā)生的 event,不再使用 select“參數(shù)-值”傳遞的方式。同時(shí),pollfd 并沒有最大數(shù)量限制(但是數(shù)量過大后性能也是會(huì)下降)。和 select 函數(shù)一樣,poll 返回后,需要輪詢 pollfd 來獲取就緒的描述符。

    從上面看,select 和 poll 都需要在返回后,通過遍歷文件描述符來獲取已經(jīng)就緒的 socket。事實(shí)上,同時(shí)連接的大量客戶端在一時(shí)刻可能只有很少的處于就緒狀態(tài),因此隨著監(jiān)視的描述符數(shù)量的增長,其效率也會(huì)線性下降。

    從本質(zhì)來說:IO 多路復(fù)用中,select()/poll()/epoll_wait()這幾個(gè)函數(shù)對應(yīng)第一階段;read()/recvfrom()對應(yīng)第二階段

    4.2IO 多路復(fù)用第一版的過程

    4.3IO 多路復(fù)用第一版的優(yōu)點(diǎn)

    IO 多路復(fù)用,主要在于復(fù)用,通過 select()或者 poll()將多個(gè) socket fds 批量通過系統(tǒng)調(diào)用傳遞給內(nèi)核,由內(nèi)核進(jìn)行循環(huán)遍歷判斷哪些 fd 上數(shù)據(jù)就緒了,然后將就緒的 readyfds 返回給用戶。再由用戶進(jìn)行挨個(gè)遍歷就緒好的 fd,讀取或者寫入數(shù)據(jù)。

    所以通過 IO 多路復(fù)用+非阻塞 IO,一方面降低了系統(tǒng)調(diào)用次數(shù),另一方面可以用極少的線程來處理多個(gè)網(wǎng)絡(luò)連接。

    4.4IO 多路復(fù)用第一版的缺點(diǎn)

    雖然第一版 IO 多路復(fù)用解決了之前提到的頻繁的系統(tǒng)調(diào)用次數(shù),但同時(shí)引入了新的問題:用戶需要每次將海量的 socket fds 集合從用戶態(tài)傳遞到內(nèi)核態(tài),讓內(nèi)核態(tài)去檢測哪些網(wǎng)絡(luò)連接數(shù)據(jù)就緒了

    但這個(gè)地方會(huì)出現(xiàn)頻繁的將海量 fd 集合從用戶態(tài)傳遞到內(nèi)核態(tài),再從內(nèi)核態(tài)拷貝到用戶態(tài)。所以,這個(gè)地方開銷也挺大。

    既然還有這個(gè)問題,那我們繼續(xù)開始解決這個(gè)問題,因此就引出了第二版的 IO 多路復(fù)用。

    其實(shí)思路也挺簡單,既然需要拷貝,那就想辦法,不拷貝。既然不拷貝,那就在內(nèi)核開辟一段區(qū)域咯

    4.5IO 多路復(fù)用第一版的區(qū)別

    select 和 poll 的區(qū)別

    1. select 能處理的最大連接,默認(rèn)是 1024 個(gè),可以通過修改配置來改變,但終究是有限個(gè);而 poll 理論上可以支持無限個(gè)
    2. select 和 poll 在管理海量的連接時(shí),會(huì)頻繁的從用戶態(tài)拷貝到內(nèi)核態(tài),比較消耗資源。

    5.IO 多路復(fù)用第二版

    IO 多路復(fù)用第二版主要指 epoll,epoll 的出現(xiàn)也是隨著內(nèi)核版本迭代才誕生的,在網(wǎng)上到處看到,epoll 是內(nèi)核 2.6 以后開始支持的

    epoll 的出現(xiàn)是為了解決前面提到的 IO 多路復(fù)用第一版的問題

    5.1IO 多路復(fù)用第二版的概念

    epoll 提供的 api

    //創(chuàng)建epollFd,底層是在內(nèi)核態(tài)分配一段區(qū)域,底層數(shù)據(jù)結(jié)構(gòu)紅黑樹+雙向鏈表
    int epoll_create(int size);//創(chuàng)建一個(gè)epoll的句柄,size用來告訴內(nèi)核這個(gè)監(jiān)聽的數(shù)目一共有多大
    
    //往紅黑樹中增加、刪除、更新管理的socket fd
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    
    //這個(gè)api是用來在第一階段阻塞,等待就緒的fd。
    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    
    1. int epoll_create(int size);
    創(chuàng)建一個(gè)epoll的句柄,size用來告訴內(nèi)核這個(gè)監(jiān)聽的數(shù)目一共有多大,這個(gè)參數(shù)不同于select()中的第一個(gè)參數(shù),給出最大監(jiān)聽的fd+1的值,參數(shù)size并不是限制了epoll所能監(jiān)聽的描述符最大個(gè)數(shù),只是對內(nèi)核初始分配內(nèi)部數(shù)據(jù)結(jié)構(gòu)的一個(gè)建議。
    當(dāng)創(chuàng)建好epoll句柄后,它就會(huì)占用一個(gè)fd值,在linux下如果查看/proc/進(jìn)程id/fd/,是能夠看到這個(gè)fd的,所以在使用完epoll后,必須調(diào)用close()關(guān)閉,否則可能導(dǎo)致fd被耗盡。
    
    2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    函數(shù)是對指定描述符fd執(zhí)行op操作。
    - epfd:是epoll_create()的返回值。
    - op:表示op操作,用三個(gè)宏來表示:添加EPOLL_CTL_ADD,刪除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分別添加、刪除和修改對fd的監(jiān)聽事件。
    - fd:是需要監(jiān)聽的fd(文件描述符)
    - epoll_event:是告訴內(nèi)核需要監(jiān)聽什么事,struct epoll_event結(jié)構(gòu)如下:
    
    struct epoll_event {
      __uint32_t events;  /* Epoll events */
      epoll_data_t data;  /* User data variable */
    };
    
    //events可以是以下幾個(gè)宏的集合:
    EPOLLIN :表示對應(yīng)的文件描述符可以讀(包括對端SOCKET正常關(guān)閉);
    EPOLLOUT:表示對應(yīng)的文件描述符可以寫;
    EPOLLPRI:表示對應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀(這里應(yīng)該表示有帶外數(shù)據(jù)到來);
    EPOLLERR:表示對應(yīng)的文件描述符發(fā)生錯(cuò)誤;
    EPOLLHUP:表示對應(yīng)的文件描述符被掛斷;
    EPOLLET: 將EPOLL設(shè)為邊緣觸發(fā)(Edge Triggered)模式,這是相對于水平觸發(fā)(Level Triggered)來說的。
    EPOLLONESHOT:只監(jiān)聽一次事件,當(dāng)監(jiān)聽完這次事件之后,如果還需要繼續(xù)監(jiān)聽這個(gè)socket的話,需要再次把這個(gè)socket加入到EPOLL隊(duì)列里
    
    3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    等待epfd上的io事件,最多返回maxevents個(gè)事件。
    參數(shù)events用來從內(nèi)核得到事件的集合,maxevents告之內(nèi)核這個(gè)events有多大,這個(gè)maxevents的值不能大于創(chuàng)建epoll_create()時(shí)的size,參數(shù)timeout是超時(shí)時(shí)間(毫秒,0會(huì)立即返回,-1將不確定,也有說法說是永久阻塞)。該函數(shù)返回需要處理的事件數(shù)目,如返回0表示已超時(shí)。
    
    

    二 工作模式

    epoll 對文件描述符的操作有兩種模式:LT(level trigger)和 ET(edge trigger)。LT 模式是默認(rèn)模式,LT 模式與 ET 模式的區(qū)別如下:   LT 模式:當(dāng) epoll_wait 檢測到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序可以不立即處理該事件。下次調(diào)用 epoll_wait 時(shí),會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。   ET 模式:當(dāng) epoll_wait 檢測到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序必須立即處理該事件。如果不處理,下次調(diào)用 epoll_wait 時(shí),不會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。

    1. LT 模式

    LT(level triggered)是缺省的工作方式,并且同時(shí)支持 block 和 no-block socket.在這種做法中,內(nèi)核告訴你一個(gè)文件描述符是否就緒了,然后你可以對這個(gè)就緒的 fd 進(jìn)行 IO 操作。如果你不作任何操作,內(nèi)核還是會(huì)繼續(xù)通知你的。

    1. ET 模式

    ET(edge-triggered)是高速工作方式,只支持 no-block socket。在這種模式下,當(dāng)描述符從未就緒變?yōu)榫途w時(shí),內(nèi)核通過 epoll 告訴你。然后它會(huì)假設(shè)你知道文件描述符已經(jīng)就緒,并且不會(huì)再為那個(gè)文件描述符發(fā)送更多的就緒通知,直到你做了某些操作導(dǎo)致那個(gè)文件描述符不再為就緒狀態(tài)了(比如,你在發(fā)送,接收或者接收請求,或者發(fā)送接收的數(shù)據(jù)少于一定量時(shí)導(dǎo)致了一個(gè) EWOULDBLOCK 錯(cuò)誤)。但是請注意,如果一直不對這個(gè) fd 作 IO 操作(從而導(dǎo)致它再次變成未就緒),內(nèi)核不會(huì)發(fā)送更多的通知(only once)

    ET 模式在很大程度上減少了 epoll 事件被重復(fù)觸發(fā)的次數(shù),因此效率要比 LT 模式高。epoll 工作在 ET 模式的時(shí)候,必須使用非阻塞套接口,以避免由于一個(gè)文件句柄的阻塞讀/阻塞寫操作把處理多個(gè)文件描述符的任務(wù)餓死。

    5.2IO 多路復(fù)用第二版的過程

    當(dāng) epoll_wait()調(diào)用后會(huì)阻塞,然后完了當(dāng)返回時(shí),會(huì)返回了哪些 fd 的數(shù)據(jù)就緒了,用戶只需要遍歷就緒的 fd 進(jìn)行讀寫即可。

    5.3IO 多路復(fù)用第二版的優(yōu)點(diǎn)

    IO 多路復(fù)用第二版 epoll 的優(yōu)點(diǎn)在于:

    一開始就在內(nèi)核態(tài)分配了一段空間,來存放管理的 fd,所以在每次連接建立后,交給 epoll 管理時(shí),需要將其添加到原先分配的空間中,后面再管理時(shí)就不需要頻繁的從用戶態(tài)拷貝管理的 fd 集合。通通過這種方式大大的提升了性能。

    所以現(xiàn)在的 IO 多路復(fù)用主要指 epoll

    5.4IO 多路復(fù)用第二版的缺點(diǎn)

    個(gè)人猜想: 如何降低占用的空間

    6.異步 IO

    6.1 異步 IO 的過程

    前面介紹的所有網(wǎng)絡(luò) IO 都是同步 IO,因?yàn)楫?dāng)數(shù)據(jù)在內(nèi)核態(tài)就緒時(shí),在內(nèi)核態(tài)拷貝用用戶態(tài)的過程中,仍然會(huì)有短暫時(shí)間的阻塞等待。而異步 IO 指:內(nèi)核態(tài)拷貝數(shù)據(jù)到用戶態(tài)這種方式也是交給系統(tǒng)線程來實(shí)現(xiàn),不由用戶線程完成,目前只有 windows 系統(tǒng)的 IOCP 是屬于異步 IO。

    7.網(wǎng)絡(luò) IO 各種模型

    7.1 reactor 模型

    目前 reactor 模型有以下幾種實(shí)現(xiàn)方案:

    1. 單 reactor 單線程模型
    2. 單 reactor 多線程模型
    3. multi-reactor 多線程模型
    4. multi-reactor 多進(jìn)程模型

    下文網(wǎng)絡(luò)模型的圖,均摘自這篇文章

    7.1.1 單 reactor 單線程模型

    此種模型,通常是只有一個(gè) epoll 對象,所有的接收客戶端連接客戶端讀取客戶端寫入操作都包含在一個(gè)線程內(nèi)。該種模型也有一些中間件在用,比如 redis

    但在目前的單線程 Reactor 模式中,不僅 I/O 操作在該 Reactor 線程上,連非 I/O 的業(yè)務(wù)操作也在該線程上進(jìn)行處理了,這可能會(huì)大大延遲 I/O 請求的響應(yīng)。所以我們應(yīng)該將非 I/O 的業(yè)務(wù)邏輯操作從 Reactor 線程上卸載,以此來加速 Reactor 線程對 I/O 請求的響應(yīng)。

    7.1.2 單 reactor 多線程模型

    該模型主要是通過將,前面的模型進(jìn)行改造,將讀寫的業(yè)務(wù)邏輯交給具體的線程池來實(shí)現(xiàn),這樣可以顯示 reactor 線程對 IO 的響應(yīng),以此提升系統(tǒng)性能

    在工作者線程池模式中,雖然非 I/O 操作交給了線程池來處理,但是所有的 I/O 操作依然由 Reactor 單線程執(zhí)行,在高負(fù)載、高并發(fā)或大數(shù)據(jù)量的應(yīng)用場景,依然較容易成為瓶頸。所以,對于 Reactor 的優(yōu)化,又產(chǎn)生出下面的多線程模式。

    7.1.3 multi-reactor 多線程模型

    在這種模型中,主要分為兩個(gè)部分:mainReactor、subReactors。mainReactor 主要負(fù)責(zé)接收客戶端的連接,然后將建立的客戶端連接通過負(fù)載均衡的方式分發(fā)給 subReactors,

    subReactors 來負(fù)責(zé)具體的每個(gè)連接的讀寫

    對于非 IO 的操作,依然交給工作線程池去做,對邏輯進(jìn)行解耦

    mainReactor 對應(yīng) Netty 中配置的 BossGroup 線程組,主要負(fù)責(zé)接受客戶端連接的建立。一般只暴露一個(gè)服務(wù)端口,BossGroup 線程組一般一個(gè)線程工作即可 subReactor 對應(yīng) Netty 中配置的 WorkerGroup 線程組,BossGroup 線程組接受并建立完客戶端的連接后,將網(wǎng)絡(luò) socket 轉(zhuǎn)交給 WorkerGroup 線程組,然后在 WorkerGroup 線程組內(nèi)選擇一個(gè)線程,進(jìn)行 I/O 的處理。WorkerGroup 線程組主要處理 I/O,一般設(shè)置 2*CPU 核數(shù)個(gè)線程

    7.2 proactor 模型

    proactor 主要是通過對異步 IO 的封裝的一種模型,它需要底層操作系統(tǒng)的支持,目前只有 windows 的 IOCP 支持的比較好。詳細(xì)的介紹可以參考這篇文章

    7.3 主流的中間件所采用的網(wǎng)絡(luò)模型

    7.4 主流網(wǎng)絡(luò)框架

    • netty
    • gnet
    • libevent
    • evio(golang)
    • ACE(c++)
    • boost::asio(c++)
    • muduo (linux only)

    關(guān)于c++和c的上述幾個(gè)庫對比,感興趣的話大家可以自行搜索資料。


    8.參考資料

    1. IO 模式和 IO 多路復(fù)用
    2. Linux IO 模式及 select、poll、epoll 詳解
    3. Chapter 6. I/O Multiplexing: The select and poll Functions
    4. 高性能 IO 模型分析-Reactor 模式和 Proactor 模式(二)
網(wǎng)站首頁   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號(hào):冀ICP備2024067069號(hào)-3 北京科技有限公司版權(quán)所有