一、前言
最近在學習Redis
,這篇文章就來簡單聊聊一道常考的面試題——Redis
為什么是單線程的。廢話不多說,直接開始吧。
二、正文
2.1 為什么需要多線程
首先,現在的CPU
一般都是由多個核心組成,每個核心可以認為是一個獨立的處理器,它們能夠並行地處理任務。所以,如果我們的CPU
是多核的,但是程序是單線程的,那么執行程序時,這個線程在某一個時刻只能在一個核心上運行,而其它的核心卻是空閑的(如果沒有其他程序的話)。所以,為了提高CPU
的使用率,我們可以創建多個線程,每個線程處理任務的一部分(每個部分互不依賴),而每個核心執行一個線程,此時CPU
的使用率將提高,程序的運行速度自然也就加快了。
除此之外,假設我們的程序有A、B、C
三個任務需要執行,但是由於我們的程序使用的是單線程,這些任務只能輪流執行,A
執行完畢只后,才能執行B
,B
執行完畢只后,才能執行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
直接操作內存中的數據,所以使用多線程並不能有效提升效率,相反,使用多線程反倒會因為需要進行線程的切換而降低效率。
除此之外,使用多線程的話,多個線程間進行同步,保證線程的安全,也是需要開銷的。尤其是Redis
的數據結構都是一些實現較為簡單的集合結構,若使用多線程,將會頻繁地發生線程沖突,線程的競爭頻率較高,反倒會拖慢Redis
的響應速度。
綜上所述,Redis
為了保持簡單和高效,自然而然地就使用了單線程。
2.4 Redis如何提高CPU的使用率
前面也提過,現在的CPU
一般都有多個核心,每個核心可以單獨執行。Redis
處理客戶端請求使用單線程,那么自然而然,無法將CPU
的所有核心都占用,也就造成了資源的浪費。而解決的方式也比較簡單,我們可以在同一個服務器上開啟多個Redis
程序,每個Redis
程序使用不同的端口,相互獨立,以此提高CPU
的使用率。而這多個Redis
程序可以配置成主從節點,共同為一個程序服務,也可以相互獨立,服務於多個程序。
三、總結
以上就對Redis
為何使用單線程,做了一個大致的介紹,總的來說,Redis
使用單線程的原因就是:多線程並不能有效提升Redis的性能,相反可能還會降低性能,所以自然而然使用單線程。希望這篇博客對有需要的人有所幫助 ,若存在錯誤或者不足,歡迎指正和補充。