與Java
中的HashSet
一樣,無序且存儲元素不重復。其底層有兩種實現方式,當value
是整數值時,且數據量不大時使用inset
來存儲,其他情況都是用字典dict
來存儲。
inset
Redis
中inset
的結構定義如下所示:
typedf struct inset{
uint32_t encoding;//編碼方式 有三種 默認 INSET_ENC_INT16
uint32_t length;//集合元素個數
int8_t contents[];//實際存儲元素的數組
//元素類型並不一定是ini8_t類型,柔性數組不占intset結構體大小,並且數組中的元
//素從小到大排列
}inset;
#define INTSET_ENC_INT16 (sizeof(int16_t)) //16位,2個字節,表示范圍-32,768~32,767
#define INTSET_ENC_INT32 (sizeof(int32_t)) //32位,4個字節,表示范
//圍-2,147,483,648~2,147,483,647
#define INTSET_ENC_INT64 (sizeof(int64_t)) //64位,8個字節,表示范
//圍-9,223,372,036,854,775,808~9,223,372,036,854,775,807
編碼格式encoding
:共有三種,INTSET_ENC_INT16
、INSET_ENC_INT32
和INSET_ENC_INT64
三種,分別對應不同的范圍。Redis
為了盡可能地節省內存,會根據插入數據的大小選擇不一樣的類型來進行存儲。
元素數量length
:記錄了保存數據的數組contents
中共有多少個元素,這樣獲取個數的時間復雜度就是O(1)
。
數組contents
:真正存儲數據的地方,數組是按照從小到大有序排列的,並且不包含任何重復項。
intset
的示意圖如下所示:
inset中整數的升級過程
這個過程可以參考這位小姐姐寫的文章,配圖食用,效果更加。整體流程總結如下:
- 了解舊的存儲格式,計算出目前已有元素占用內存大小,計算規則是length * encoding,如 4* 16=64;
- 確定新的編碼格式,當原有的編碼格式不能存儲下新增的數據時,此時就要選擇新的合適的編碼格式;
- 根據新的編碼格式計算出需要新增的內存大小,然后從尾部將數據插入;
- 根據新的編碼格式重置之前的值,此時
contents
存在兩種編碼格式設置的值,就需要進行統一,從插入新數據的起始位置開始,從后向前將之前的數據按照新的編碼格式進行移動和設置。從后往前是為了防止數據被覆蓋。
優點:根據存入的數據大小選擇合適的編碼方式,且只在必要的時候進行升級操作,節省內存
缺點:升級過程耗費系統資源,還有就是不支持降級,一旦升級就不可以降級