淺析對(duì)redis?hashtable?的sizemask理解
在 Redis 的哈希表實(shí)現(xiàn)中,index = hash & dict->ht[0].sizemask 是計(jì)算鍵值對(duì)應(yīng)存儲(chǔ)位置的核心操作。這個(gè)操作看起來簡(jiǎn)單,但背后涉及哈希表的內(nèi)存布局和性能優(yōu)化策略。我們通過以下步驟逐步解析其原理:
一、哈希表的設(shè)計(jì)目標(biāo)
- 快速定位桶(Bucket):通過鍵的哈希值直接找到對(duì)應(yīng)的存儲(chǔ)位置,時(shí)間復(fù)雜度接近 O(1)。
- 均勻分布鍵值對(duì):減少哈希沖突,避免鏈表過長(zhǎng)導(dǎo)致性能下降。
- 高效計(jì)算:避免使用耗時(shí)的取模運(yùn)算(
%)。
二、哈希表大?。╯ize)的特殊性
Redis 的哈希表大小 size 始終是 2 的冪(如 4, 8, 16, 32 等)。這種設(shè)計(jì)有兩個(gè)關(guān)鍵優(yōu)勢(shì):
- 快速計(jì)算索引:用位運(yùn)算(
&)替代取模運(yùn)算(%)。 - 均勻分布哈希值:減少哈希沖突的概率。
三、sizemask 的作用
• 定義:sizemask = size - 1
• 二進(jìn)制特征:當(dāng) size 是 2 的冪時(shí),sizemask 的二進(jìn)制形式為全 1。
例如:
• size = 8 → sizemask = 7 → 二進(jìn)制 0111
• size = 16 → sizemask = 15 → 二進(jìn)制 1111
四、索引計(jì)算原理
1. 取模運(yùn)算的替代方案
傳統(tǒng)哈希索引計(jì)算使用取模運(yùn)算:
index = hash % size; // 例如 hash=10, size=8 → index=2
但取模運(yùn)算在計(jì)算機(jī)中效率較低(涉及除法操作)。
2. 位運(yùn)算優(yōu)化
當(dāng) size 是 2 的冪時(shí),可以用位運(yùn)算替代:
index = hash & (size - 1); // 即 hash & sizemask
為什么這等價(jià)于取模?
• 因?yàn)?size 是 2 的冪,size - 1 的二進(jìn)制形式為全 1(例如 size=8 對(duì)應(yīng) sizemask=7,二進(jìn)制 0111)。
• hash & sizemask 相當(dāng)于保留哈希值的低 n 位(n = log2(size)),結(jié)果范圍是 0 ≤ index < size,與 hash % size 等價(jià)。
五、具體示例
假設(shè)哈希表大小 size = 8(即 sizemask = 7),哈希值 hash = 10:
| 步驟 | 二進(jìn)制表示 | 結(jié)果 |
|---|---|---|
hash = 10 | 1010 | 10 |
sizemask = 7 | 0111 | 7 |
hash & sizemask | 1010 & 0111 = 0010 | 2 |
結(jié)果與 10 % 8 = 2 完全一致,但位運(yùn)算比取模運(yùn)算快得多。
六、哈希表擴(kuò)容時(shí)的行為
當(dāng)哈希表需要擴(kuò)容(例如從 size=8 擴(kuò)容到 size=16):
新 sizemask = 15(二進(jìn)制 1111)。哈希值相同的鍵會(huì)分散到更多桶中:
• 例如原哈希值 10(二進(jìn)制 1010)在 size=8 時(shí)索引為 2。
• 擴(kuò)容后 size=16,索引變?yōu)?10 & 15 = 10。
七、為什么必須保證 size 是 2 的冪?
如果 size 不是 2 的冪,sizemask 的二進(jìn)制形式將包含 0,導(dǎo)致部分索引永遠(yuǎn)無法被映射到。
例如:
• size = 7 → sizemask = 6(二進(jìn)制 0110)
• 哈希值 5(二進(jìn)制 0101)→ 0101 & 0110 = 0100(索引 4)
• 哈希值 3(二進(jìn)制 0011)→ 0011 & 0110 = 0010(索引 2)
• 索引 1、3、5、7 永遠(yuǎn)無法被訪問,導(dǎo)致哈希分布不均。
八、性能對(duì)比
| 操作類型 | 指令周期(近似) | 適用場(chǎng)景 |
|---|---|---|
位運(yùn)算(&) | 1 cycle | 快速計(jì)算 |
取模運(yùn)算(%) | 10-20 cycles | 通用計(jì)算 |
在 Redis 這種高性能場(chǎng)景下,位運(yùn)算的優(yōu)勢(shì)顯著。
九、總結(jié)
• sizemask = size - 1:當(dāng) size 是 2 的冪時(shí),此公式成立。
• hash & sizemask:快速計(jì)算鍵的存儲(chǔ)位置,避免取模運(yùn)算。
• 設(shè)計(jì)優(yōu)勢(shì):內(nèi)存對(duì)齊、哈希均勻、計(jì)算高效。
這種設(shè)計(jì)是 Redis 哈希表高性能的核心保障,結(jié)合漸進(jìn)式 rehash 機(jī)制,使得 Redis 能夠高效處理大規(guī)模鍵值對(duì)存儲(chǔ)。
到此這篇關(guān)于redis hashtable 的sizemask理解的文章就介紹到這了,更多相關(guān)redis hashtable 的sizemask內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis過期事件監(jiān)聽器的完整實(shí)現(xiàn)步驟
要使用 Redis 過期事件監(jiān)聽器來更新數(shù)據(jù)庫狀態(tài),我們需要確保 Redis 的事件通知已啟用,并實(shí)現(xiàn)監(jiān)聽器來捕獲過期的鍵,并根據(jù)需要更新數(shù)據(jù)庫,本文給大家介紹了Redis過期事件監(jiān)聽器的完整實(shí)現(xiàn)步驟,需要的朋友可以參考下2024-10-10
redis+lua實(shí)現(xiàn)分布式限流的示例
本文主要介紹了redis+lua實(shí)現(xiàn)分布式限流的示例,可以實(shí)現(xiàn)復(fù)雜的限流邏輯,如滑動(dòng)窗口限流,并且避免了多步操作導(dǎo)致的并發(fā)問題,具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
Redis創(chuàng)建并修改Lua 環(huán)境的實(shí)現(xiàn)方法
為了在Redis服務(wù)器中執(zhí)行Lua腳本, Redis在服務(wù)器內(nèi)嵌了一個(gè)Lua環(huán)境, 并對(duì)這個(gè)Lua環(huán)境進(jìn)行了一系列修改,本文主要介紹了Redis創(chuàng)建并修改Lua 環(huán)境的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05
一文搞懂Redis中的慢查詢?nèi)罩竞捅O(jiān)視器
我們都知道MySQL有慢查詢?nèi)罩?但Redis也有慢查詢?nèi)罩?可用于監(jiān)視和優(yōu)化查詢,本文給大家詳細(xì)介紹了Redis中的慢查詢?nèi)罩竞捅O(jiān)視器,文章通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-04-04
SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象的操作方法
這篇文章主要介紹了SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
Redis 哨兵機(jī)制及配置實(shí)現(xiàn)
本文主要介紹了Redis 哨兵機(jī)制及配置實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

