Redis為什麼是單線程的
一、前言
最近在學習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
直接操作內存中的數據,所以使用多線程並不能有效提升效率,相反,使用多線程反倒會因為需要進行線程的切換而降低效率。
有人可能會疑惑,數據是由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的性能,相反可能還會降低性能,所以自然而然使用單線程。希望這篇博客對有需要的人有所幫助 ,若存在錯誤或者不足,歡迎指正和補充。
四、參考
- 《Java並發編程的藝術》
- //blog.csdn.net/u011663149/article/details/85307615