理解 redis 中的 哈希对象类型
redis中的hash也是我們使用中的高頻數(shù)據(jù)結(jié)構(gòu),它的構(gòu)造基本上和編程語言中的HashTable,Dictionary大同小異,如果大家往后有什么邏輯需要用Dictionary存放的話,可以根據(jù)場(chǎng)景優(yōu)先考慮下redis哦,起碼可以裝裝嘛,現(xiàn)在我默認(rèn)你已經(jīng)有裝的沖動(dòng)了,打開redis手冊(cè),看看有哪些我們用得到的裝方法。
一:常用方法
只要是一個(gè)數(shù)據(jù)結(jié)構(gòu),最基礎(chǔ)的永遠(yuǎn)是CURD,redis中的insert和update,永遠(yuǎn)只需要set來替代,比如下面的Hset,如下圖:
前面幾篇文章我都沒有挑選一個(gè)方法仔細(xì)講解,其實(shí)也沒什么好講解的,就好似C#中的一個(gè)類的一個(gè)方法而已,知道傳遞一些啥參數(shù)就OK了,就比如要說的HSet,它的格式如下:
接下來我在CentOS里面操作一下,
[administrator@localhost?redis-3.0.5]$?src/redis-cli 127.0.0.1:6379>?clear127.0.0.1:6379>?hset?person?name?jack (integer)?1 127.0.0.1:6379>?hset?person?age?20 (integer)?1 127.0.0.1:6379>?hset?person?sex?famale (integer)?1 127.0.0.1:6379>?hgetall?person 1)?"name" 2)?"jack" 3)?"age" 4)?"20" 5)?"sex" 6)?"famale" 127.0.0.1:6379>?hkeys?person 1)?"name" 2)?"age" 3)?"sex" 127.0.0.1:6379>?hvals?person 1)?"jack" 2)?"20" 3)?"famale" 127.0.0.1:6379>或許有人看了上面的console有一點(diǎn)疑惑,那就是前面有幾個(gè)參數(shù),比如person,name啦,然后才是value,如果你看了第一篇的話,你大概就明白了,其實(shí)在redis的這個(gè)層面,它永遠(yuǎn)只有一個(gè)鍵,一個(gè)值,這個(gè)鍵永遠(yuǎn)都是字符串對(duì)象,也就是SDS對(duì)象,而值的種類就多了,有字符串對(duì)象,有隊(duì)列對(duì)象,還有這篇的hash對(duì)象,往后的有序集合對(duì)象等等,如果你還不明白的話,轉(zhuǎn)化為C#語言就是。
var?person=new?Dictionary<string,string>(); person.Add("name","jack"); ...調(diào)用方法就是這么的簡單,關(guān)鍵在于時(shí)不時(shí)的需要你看一看手冊(cè),其實(shí)最重要的是了解下它在redis源碼中的原理就好了。
二:探索原理
hash的源代碼是在 dict.h 文件下,枚舉如下:
typedef?struct?dictEntry?{void?*key;union?{void?*val;uint64_t?u64;int64_t?s64;double?d;}?v;struct?dictEntry?*next; }?dictEntry;typedef?struct?dictType?{unsigned?int?(*hashFunction)(const?void?*key);void?*(*keyDup)(void?*privdata,?const?void?*key);void?*(*valDup)(void?*privdata,?const?void?*obj);int?(*keyCompare)(void?*privdata,?const?void?*key1,?const?void?*key2);void?(*keyDestructor)(void?*privdata,?void?*key);void?(*valDestructor)(void?*privdata,?void?*obj); }?dictType;/*?This?is?our?hash?table?structure.?Every?dictionary?has?two?of?this?as?we*?implement?incremental?rehashing,?for?the?old?to?the?new?0.?*/ typedef?struct?dictht?{dictEntry?**table;unsigned?long?size;unsigned?long?sizemask;unsigned?long?used; }?dictht;typedef?struct?dict?{dictType?*type;void?*privdata;dictht?ht[2];long?rehashidx;?/*?rehashing?not?in?progress?if?rehashidx?==?-1?*/int?iterators;?/*?number?of?iterators?currently?running?*/ }?dict;/*?If?safe?is?set?to?1?this?is?a?safe?iterator,?that?means,?you?can?call*?dictAdd,?dictFind,?and?other?functions?against?the?dictionary?even?while*?iterating.?Otherwise?it?is?a?non?safe?iterator,?and?only?dictNext()*?should?be?called?while?iterating.?*/ typedef?struct?dictIterator?{dict?*d;long?index;int?table,?safe;dictEntry?*entry,?*nextEntry;/*?unsafe?iterator?fingerprint?for?misuse?detection.?*/long?long?fingerprint; }?dictIterator;上面就是我們使用hash的源代碼數(shù)據(jù)結(jié)構(gòu),接下來我來擼一擼其中的邏輯關(guān)系。
1. dict結(jié)構(gòu)
typedef?struct?dict?{dictType?*type;void?*privdata;dictht?ht[2];long?rehashidx;?/*?rehashing?not?in?progress?if?rehashidx?==?-1?*/int?iterators;?/*?number?of?iterators?currently?running?*/ }?dict;這個(gè)結(jié)構(gòu)是hash的真正的底層數(shù)據(jù)結(jié)構(gòu),可以看到其中有5個(gè)屬性。
dictType *type
可以看到它的類型是dictType,從上面你也可以看到,它是有枚舉結(jié)構(gòu)定義的,如下:
typedef?struct?dictType?{unsigned?int?(*hashFunction)(const?void?*key);void?*(*keyDup)(void?*privdata,?const?void?*key);void?*(*valDup)(void?*privdata,?const?void?*obj);int?(*keyCompare)(void?*privdata,?const?void?*key1,?const?void?*key2);void?(*keyDestructor)(void?*privdata,?void?*key);void?(*valDestructor)(void?*privdata,?void?*obj); }?dictType;從上面這個(gè)數(shù)據(jù)結(jié)構(gòu)中你可以看到里面都是一些方法,但是有一個(gè)非常重要的方法,那就是第一個(gè)hashFunction,可以看到它就是計(jì)算hash值的,跟C#中的dictionary中求hash值一樣一樣的。
dictht ht[2]
你可能會(huì)疑問,為什么這個(gè)屬性是2個(gè)大小的數(shù)組呢,其實(shí)正真使用的是 ht[0],而ht[1]是用于擴(kuò)容hash表時(shí)的暫存數(shù)組,這一點(diǎn)也很奇葩,同時(shí)也很精妙,redis為什么會(huì)這么做呢???仔細(xì)想想你可能會(huì)明白,擴(kuò)容有兩種方法,要么一次性擴(kuò)容,要么漸進(jìn)性擴(kuò)容,后面這種擴(kuò)容是什么意思呢?就是我在擴(kuò)容的同時(shí)不影響前端的CURD,我慢慢的把數(shù)據(jù)從ht[0]轉(zhuǎn)移到ht[1]中,同時(shí)rehashindex來記錄轉(zhuǎn)移的情況,當(dāng)全部轉(zhuǎn)移完成之后,將ht[1]改成ht[0]使用,就這么簡單。
2. dicth結(jié)構(gòu)
typedef?struct?dictht?{dictEntry?**table;unsigned?long?size;unsigned?long?sizemask;unsigned?long?used; }?dictht;dictEntry **table;
從上面這個(gè)結(jié)構(gòu)體中,你可以看到一個(gè)非常重要的屬性:dictEntry **table, 其中table是一個(gè)數(shù)組,數(shù)組類型是dictEntry,既然是一個(gè)數(shù)組,那后面的三個(gè)屬性就好理解了,size是數(shù)組的大小,sizemask和數(shù)組求模有關(guān),used記錄數(shù)組中已使用的大小,現(xiàn)在我們把注意力放在dictEntry這個(gè)數(shù)組實(shí)體類型上面。
3. dictEntry結(jié)構(gòu)
typedef?struct?dictEntry?{void?*key;union?{void?*val;uint64_t?u64;int64_t?s64;double?d;}?v;struct?dictEntry?*next; }?dictEntry;從這個(gè)數(shù)據(jù)結(jié)構(gòu)上面你可以看到有三個(gè)大屬性。
第一個(gè)就是:*key:它就是hash表中的key。
第二個(gè)就是:union的*val 就是hash的value。
第三個(gè)就是:*next就是為了防止hash沖突采用的掛鏈?zhǔn)侄巍?/p>
這個(gè)原理和C#中的Dictionary還是一樣一樣的。
不知道你看懂了沒有,如果總結(jié)上面描述的話,我可以畫出如下的hash結(jié)構(gòu)圖。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的理解 redis 中的 哈希对象类型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Azure Show】|第七期 特别版
- 下一篇: prometheus-net.DotNe