字典,又稱為符號表(symbol table),關聯陣列(associative array)或對映(map),是一種用來儲存鍵值對(key-value-pair)的抽象資料結構。字典中的鍵不會重複。
接下來會分析redis中字典的實現方式,雜湊演算法,解決鍵衝突的方法及rehash的過程。文中展示的 redis 原始碼均來自 3.0.4 版本。
redis 的字典使用雜湊表作為底層實現,乙個雜湊表裡面可以有多個結點,每個結點儲存了乙個鍵值對。
typedef
struct dictht dictht;
table 是乙個陣列,陣列中每個元素其實都是乙個鍊錶的頭指標。鍊錶中每個結點都儲存著乙個鍵值對。
size 屬性記錄了table陣列的大小,redis的擴容和收縮機制,保證了 size 總是為 2^n。
sizemask 是用於計算索引值的掩碼,總是等於 size-1。
used 記錄了雜湊表中結點的數量,即所有鍊錶中結點的總數。
當有兩個或以上數量的鍵被分配到了同乙個索引上面時,我們稱這些鍵發生了衝突。比如上圖中 k2 和 k0。
redis 使用鏈位址法解決衝突。每個節點都有乙個 next 指標,多個衝突的結點通過 next 指標構成乙個單向鍊錶,這樣就解決了鍵衝突的問題。
負載因子:雜湊表中單向鍊錶的平均長度。隨著增刪操作的進行,redis 通過 rehash 操作將負載因子維持在乙個合理的範圍內。rehash操作分為兩種:
typedef
struct dict
;
rehash 過程如下:
將 ht[0] 中所有鍵值對移動到 ht[1] 中:根據 ht[1].sizemask 重新計算雜湊值與索引值;根據新的索引值將鍵值對插入到 ht[1] 中;將鍵值對從 ht[0] 中刪除。
當 ht[0] 中所有鍵值對移動到 ht[1] 之後開始執行清理工作:釋放 ht[0] 占用的記憶體;將 ht[1] 賦值給 ht[0];為 ht[1] 分配乙個空的雜湊表,為下一次 rehash 做準備。
擴充套件或收縮雜湊表需要將 ht[0] 的所有鍵值對移動到 ht[1] 當中。這個動作是分多次,漸進式地完成的。原因在於當鍵值對過多時,一次性移動所有鍵值對會導致redis在一段時間內無法對外提供服務。
漸進式 rehash 步驟如下:
特別的,在漸進式 rehash 操作過程中,因為同時存在兩個雜湊表,所以字典的刪除,查詢,更新操作會在兩個雜湊表上進行。程式會先嘗試在 ht[0] 中尋找目標鍵值對,如果沒有找到則會在 ht[1] 再次進行尋找,然後進行具體操作。但是新增操作只會在 ht[1] 上進行,這保證了 ht[0] 中的已經被清空的單向鍊錶不會新增元素。
每日一講 Python系列 字典
usr bin python coding utf 8 data structure dict to define a dict,use symbol stored by k v form.so,while index method,such as list tuple,is invalid.we ...
面試官 講一講Mybatis外掛程式的原理及如何實現?
public inte ce interceptor intercepts 註解標記這是乙個 其中可以指定多個 signature signature 指定該 攔截的是四大物件中的哪個方法 type 的四大物件的型別 method 的方法,方法名 args 入參的型別,可以是多個,根據方法的引數指定...
牛客堂常見面試題精講(一)1
順時針旋轉列印矩陣 演算法 package com.zhao.niuke public class problem 02 rotatematrix public static void rotateedge int m,int tr,int tc,int dr,int dc public stati...