redis在2.8.0版本新增了眾望所歸的scan操作,從此再也不用擔心敲入了keys*, 然後舉起雙手看著鍵盤等待漫長的系統卡死了···
命令的官方介紹在這裡, 中文版由huangz同學細心翻譯了,作者antirez的介紹在這裡:finally redis collections are iterable (我又**的想到了之前他那次機器down機的事故了···)。
redis的scan操作由於其整體的資料設計,無法提供特別準的scan操作,僅僅是乙個「can 『 t guarantee , just do my best」的實現,優缺點如下:
缺點:所以結論是scan是乙個不錯的但也讓人又愛又恨的命令···。下面來介紹一下**。
首先scancommand 函式處理簡單的scan操作,其他類似hscan函式跟這個的區別就是hscan需要取獲取一遍key對應的空間或者說域,他們主要都是嚼用了通用的scan操作函式:scangenericcommand 。
scangenericcommand 函式分4步:
第一步當然就是解析引數了,比如count, match匹配引數;
第二部是需要去做真正的掃瞄鍵 的操作了,redis為了效能考慮,對於小資料結構會轉換為ziplist,intset資料結構因此需要區分這2類,對於後者,由於其本身比較小,因此可完全可以在這一次scan操作的時候返還所有的資料,反正不大的。
另外一類就是正常的hash表所代表的掃瞄了,其掃瞄路徑比較複雜,好吧,我看了好幾次都沒有看明白這到底是怎麼掃瞄的,這幾天啃也要啃出來!
/* handle the case of a hash table. */上面簡單的地方在於如果這個鍵是已redis_set或者redis_hash或者redis_zset行事儲存的話,那麼只需要掃瞄所有的鍵,然後乙個個將其加入到臨時的列表裡面,以備返回給客戶端。ht = null;
if (o == null) else if (o->type == redis_set && o->encoding == redis_encoding_ht) else if (o->type == redis_hash && o->encoding == redis_encoding_ht) else if (o->type == redis_zset && o->encoding == redis_encoding_skiplist)
//由於redis的ziplist, intset等型別資料量挺少,所以可用一次返回的。下面的else if 做這個事情。全部返回乙個key 。
if (ht) while (cursor && listlength(keys) < count); } else if (o->type == redis_set) else if (o->type == redis_hash || o->type == redis_zset)
cursor = 0;
} else
最難的地方在於dictscan 函式,裡面是各種位運算。
隨後第三步就是進行結果的過濾了,一般就是用match引數代表的字串去做匹配,看是否需要過濾資料。
第四步就是將收集到的資料返回給客戶端。然後就完成了請求。
好吧,我看了2次,沒看懂·····先做飯··
ps: 寫著寫著發現一篇文章寫不完,所以令起一篇了:redis scan迭代器遍歷操作原理(二)–dictscan反向二進位制迭代器 , 希望能講清楚.
迭代器遍歷
iterator物件稱為迭代器,主要用於遍歷collection 集合中的元素。所有實現了collection介面的集合類都有乙個iterator 方法,用以返回乙個實現了lterator介面的物件,即可以返回乙個迭代器。lterator的結構.iterator僅用於遍歷集合,iterator本身並...
for 迭代器遍歷list map
1 map與list區別 list是物件集合,允許物件重複。map是鍵值對的集合,不允許key重複 2 list 與 list 型別 list不限制型別,也就是object型別 list 型別 限定在某一型別,使用時不需要強轉,避免執行錯誤 注 map 與 map也是同樣的 demo1 遍歷list...
使用next遍歷迭代器
不使用for遍歷可迭代物件,而使用 next 函式並在 中捕獲 stopiteration 異常。比如,下面的例子手動讀取乙個檔案中的所有行 def manual iter with open test.txt r as f try while true line next f print line...