<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] 相信大家在面試過程中經常會被問到:“**單線程的Redis為啥這么快?**” 哈哈,反正我在面試時候經常會問候選人這個問題,這個問題其實是對redis內部機制的一個考察,可以牽扯出好多涉及底層深入原理的一些列問題。 **回到問題本身,基本的回答就兩點:** * 完全基于內存 * IO多路復用 1、關于第1點比較好理解。Redis 絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似于HashMap,查找和操作的時間復雜度都是O(1)。 2、關于第2點IO多路復用,有些同學看到概念后感覺一頭霧水,到底什么是IO多路復用? 本文從IO并發性能提升來整體思考,來逐步剖析IO多路復用的原理。 ## 一、如何快速理解IO多路復用? * 多進程 * 多線程 * 基于單進程的IO多路復用(select/poll/epoll) ### 1、多進程 對于并發情況,假如一個進程不行,那搞多個進程不就可以同時處理多個客戶端連接了么? 多進程這種方式的確可以解決了服務器在同一時間能處理多個客戶端連接請求的問題,但是仍存在一些缺點: * fork()等系統調用會使得進程上下文進行切換,效率較低 * 進程創建的數量隨著連接請求的增加而增加。比如10w個請求,就要fork 10w個進程,開銷太大 * 進程與進程之間的地址空間是私有、獨立的,使得進程之間的數據共享變得困難 ### 2、多線程 線程是運行在進程上下文的邏輯流,一個進程可以包含多個線程,多個線程運行在同一進程上下文中,因此可共享這個進程地址空間的所有內容,解決了進程與進程之間通信難的問題。 同時,由于一個線程的上下文要比一個進程的上下文小得多,所以線程的上下文切換,要比進程的上下文切換效率高得多。 ### 3、IO多路復用 簡單理解就是:一個服務端進程可以同時處理多個套接字描述符。 * **多路**:多個客戶端連接(連接就是套接字描述符) * **復用**:使用單進程就能夠實現同時處理多個客戶端的連接 以上是通過增加進程和線程的數量來并發處理多個套接字,免不了上下文切換的開銷,而IO多路復用只需要一個進程就能夠處理多個套接字,從而解決了上下文切換的問題。 其發展可以分**select->poll→epoll**三個階段來描述。 ## 二、如何簡單理解select/poll/epoll呢? 按照以往慣例,還是聯系一下我們日常中的現實場景,這樣更助于大家理解。 > **舉栗說明:** > > 領導分配員工開發任務,有些員工還沒完成。如果領導要每個員工的工作都要驗收check,那在未完成的員工那里,只能阻塞等待,等待他完成之后,再去check下一位員工的任務,造成性能問題。 **那如何解決這個問題呢?** ### 1、select > **舉栗說明:** > > 領導找個Team Leader(后文簡稱TL),負責代自己check每位員工的開發任務。 > > TL 的做法是:遍歷問各個員工“完成了么?”,完成的待CR check無誤后合并到Git分支,對于其他未完成的,休息一會兒后再去遍歷.... 這樣存在什么問題呢? * 這個TL存在能力短板問題,最多只能管理1024個員工 * 很多員工的任務沒有完成,而且短時間內也完不成的話,TL還是會不停的去遍歷問詢,影響效率。 select函數: ~~~ int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout); ~~~ select 函數監視的文件描述符分3類,分別是writefds、readfds、和exceptfds。調用后select函數會阻塞,直到有描述符就緒(有數據可讀、可寫、或者有except),或者超時(timeout指定等待時間,如果立即返回設為null即可),函數返回。當select函數返回后,可以通過遍歷fdset,來找到就緒的描述符。 select具有良好的跨平臺支持,其缺點在于單個進程能夠監視的文件描述符的數量存在最大限制,在Linux上一般為1024。 ### 2、poll > **舉栗說明:** > > 換一個能力更強的New Team Leader(后文簡稱NTL),可以管理更多的員工,這個NTL可以理解為poll。 poll函數: ~~~ intpoll(structpollfd*fds, nfds_t nfds,int timeout);typedef struct pollfd{?int fd; // 需要被檢測或選擇的文件描述符?short events; // 對文件描述符fd上感興趣的事件?short revents; // 文件描述符fd上當前實際發生的事件} pollfd_t; ~~~ poll改變了文件描述符集合的描述方式,使用了pollfd結構而不是select的fd\_set結構,使得poll支持的文件描述符集合限制遠大于select的1024。 ### 3、epoll > **舉栗說明:** > > 在上一步poll方式的NTL基礎上,改進一下NTL的辦事方法:遍歷一次所有員工,如果任務沒有完成,告訴員工待完成之后,其應該做xx操作(制定一些列的流程規范)。這樣NTL只需要定期check指定的關鍵節點就好了。這就是epoll。 Linux中提供的epoll相關函數如下: ~~~ intepoll_create(int size);intepoll_ctl(int epfd,int op,int fd,struct epoll_event *event);intepoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout); ~~~ epoll是Linux內核為處理大批量文件描述符而作了改進的poll,是Linux下多路復用IO接口select/poll的增強版本,它能顯著提高程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率。 ### 4、小結 * **select**就是輪詢,在Linux上限制個數一般為1024個 * **poll**解決了select的個數限制,但是依然是輪詢 * **epoll**解決了個數的限制,同時解決了輪詢的方式 ## 三、IO多路復用在Redis中的應用 Redis 服務器是一個事件驅動程序, 服務器處理的事件分為時間事件和文件事件兩類。 * **文件事件**:Redis主進程中,主要處理客戶端的連接請求與相應。 * **時間事件**:fork出的子進程中,處理如AOF持久化任務等。 由于Redis的文件事件是單進程,單線程模型,但是確保持著優秀的吞吐量,IO多路復用起到了主要作用。 文件事件是對套接字操作的抽象,每當一個套接字準備好執行連接應答、寫入、讀取、關閉等操作時,就會產生一個文件事件。因為一個服務器通常會連接多個套接字,所以多個文件事件有可能會并發地出現。 IO多路復用程序負責監聽多個套接字并向文件事件分派器傳送那些產生了事件的套接字。文件事件分派器接收IO多路復用程序傳來的套接字,并根據套接字產生的事件的類型,調用相應的事件處理器。示例如圖所示: ![](https://static001.geekbang.org/infoq/22/225e6ad72395a6686eba04d82bfec23f.jpeg) 文件處理器的四個組成部分 Redis的IO多路復用程序的所有功能都是通過包裝常見的select、poll、evport和kqueue這些IO多路復用函數庫來實現的,每個IO多路復用函數庫在Redis源碼中都有對應的一個單獨的文件。 Redis為每個IO多路復用函數庫都實現了相同的API,所以IO多路復用程序的底層實現是可以互換的。如圖: ![](https://static001.geekbang.org/infoq/04/04dd554ab597afc58aa94357ecec97f3.jpeg) 多個IO復用庫實現可選 Redis把所有連接與讀寫事件、還有我們沒提到的時間事件一起集中管理,并對底層IO多路復用機制進行了封裝,最終實現了單進程能夠處理多個連接以及讀寫事件。這就是IO多路復用在redis中的應用。
                  <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>

                              哎呀哎呀视频在线观看