Redis為什麼是單線程的

一、前言

  最近在學習Redis,這篇文章就來簡單聊聊一道常考的面試題——Redis為什麼是單線程的。廢話不多說,直接開始吧。

二、正文

2.1 為什麼需要多線程

  首先,現在的CPU一般都是由多個核心組成,每個核心可以認為是一個獨立的處理器,它們能夠並行地處理任務。所以,如果我們的CPU是多核的,但是程序是單線程的,那麼執行程序時,這個線程在某一個時刻只能在一個核心上運行,而其它的核心卻是空閑的(如果沒有其他程序的話)。所以,為了提高CPU的使用率,我們可以創建多個線程,每個線程處理任務的一部分(每個部分互不依賴),而每個核心執行一個線程,此時CPU的使用率將提高,程序的運行速度自然也就加快了。

  除此之外,假設我們的程序有A、B、C三個任務需要執行,但是由於我們的程序使用的是單線程,這些任務只能輪流執行,A執行完畢只後,才能執行BB執行完畢只後,才能執行C。這也就意味着,在單線程的環境下,一個新的任務,需要等待它之前的任務執行完畢之後,才能被執行。假設A任務是一個非常耗時的任務,那麼後面的B、C需要等待較長的一段時間,才能被執行,這樣的話提交B、C任務的用戶,需要等待較長的時間,才能得到響應。如果使用的是多線程,那麼每個線程被分配到不同的核心上,可以並行地執行;若核心數量不夠,CPU將採用時間片輪轉算法,輪流為每一個線程分配時間片執行,這樣後續到達的任務,也可以並發地執行,而不需要等待之前任務的完成。此時,後續到達的任務,也可以較早地得到響應,任務的響應速度變得更加均勻。

2.2 如何理解Redis的單線程

  這裡需要注意一個問題,我們所說的Redis的單線程,不是指Redis程序真的只會有一個線程。這裡所說的單線程,指的是Redis處理客戶端發來的數據操作請求(增刪改查),只會使用一個線程去執行。但是實際上,Redis在執行其他操作的時候,可能會開啟多個進程或線程,比如說持久化。Redis執行BGSAVE指令,進行快照持久化時,就會fork出一個子進程,然後子進程去創建快照,完成持久化操作。

2.3 Redis為什麼使用單線程

  官方解釋如下:因為Redis是基於內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬。既然單線程容易實現,而且CPU不會成為瓶頸,那就順理成章地採用單線程的方案了

  上面的解釋不是很好理解,我就簡單說一說我自己的理解吧。我們知道,Redis將數據存放在內存當中,這也就意味着,Redis在操作數據時,不需要進行磁盤I/O。磁盤I/O是一個比較耗時的操作,所以對於需要進行磁盤I/O的程序,我們可以使用多線程,在某個線程進行I/O時,CPU切換到當前程序的其他線程執行,以此減少CPU的等待時間。而Redis直接操作內存中的數據,所以使用多線程並不能有效提升效率,相反,使用多線程反倒會因為需要進行線程的切換而降低效率。

  有人可能會疑惑,數據是由CPU進行處理,Redis的數據存放在內存中,將內存中的數據讀入CPU時,CPU不是依然需要等待嗎,為什麼不能在等待數據從內存讀入CPU期間執行其他線程,以此提高CPU的使用率呢?這個問題的答案很簡單,內存的讀寫速度雖然比CPU慢很多,但是也是非常快的。CPU切換線程需要花費一定的時間,而多次切換線程所花費的時間,可能比直接使用單線程執行相同的任務,花費的時間要更多,這是非常不划算的。

  除此之外,使用多線程的話,多個線程間進行同步,保證線程的安全,也是需要開銷的。尤其是Redis的數據結構都是一些實現較為簡單的集合結構,若使用多線程,將會頻繁地發生線程衝突,線程的競爭頻率較高,反倒會拖慢Redis的響應速度。

  綜上所述,Redis為了保持簡單和高效,自然而然地就使用了單線程。

2.4 Redis如何提高CPU的使用率

  前面也提過,現在的CPU一般都有多個核心,每個核心可以單獨執行。Redis處理客戶端請求使用單線程,那麼自然而然,無法將CPU的所有核心都佔用,也就造成了資源的浪費。而解決的方式也比較簡單,我們可以在同一個服務器上開啟多個Redis程序,每個Redis程序使用不同的端口,相互獨立,以此提高CPU的使用率。而這多個Redis程序可以配置成主從節點,共同為一個程序服務,也可以相互獨立,服務於多個程序。

三、總結

  以上就對Redis為何使用單線程,做了一個大致的介紹,總的來說,Redis使用單線程的原因就是:多線程並不能有效提升Redis的性能,相反可能還會降低性能,所以自然而然使用單線程。希望這篇博客對有需要的人有所幫助 ,若存在錯誤或者不足,歡迎指正和補充。

四、參考

Tags: