1. 程式人生 > 資訊 >約 3668 元,三星悄悄釋出 Galaxy S20 FE 5G 手機(2022 款):搭載驍龍 865 晶片,包裝內不贈送 AKG 耳機

約 3668 元,三星悄悄釋出 Galaxy S20 FE 5G 手機(2022 款):搭載驍龍 865 晶片,包裝內不贈送 AKG 耳機

這是一個類似二分查詢的演算法,我們可以簡單的理解為是連結串列+多級索引

跳躍表 skiplist 就是受到這種多層連結串列結構的啟發而設計出來的。按照上面生成連結串列的方式,上面每一層連結串列的節點個數,是下面一層的節點個數的一半,這樣查詢過程就非常類似於一個二分查詢,使得查詢的時間複雜度可以降低到 O(logn)

但是,這種方法在插入資料的時候有很大的問題。新插入一個節點之後,就會打亂上下相鄰兩層連結串列上節點個數嚴格的 2:1 的對應關係。如果要維持這種對應關係,就必須把新插入的節點後面的所有節點 (也包括新插入的節點) 重新進行調整,這會讓時間複雜度重新蛻化成 O(n)。刪除資料也有同樣的問題。

skiplist 為了避免這一問題,它不要求上下相鄰兩層連結串列之間的節點個數有嚴格的對應關係,而是 為每個節點隨機出一個層數(level)。比如,一個節點隨機出的層數是 3,那麼就把它鏈入到第 1 層到第 3 層這三層連結串列中。為了表達清楚,下圖展示瞭如何通過一步步的插入操作從而形成一個 skiplist 的過程:

https://zhuanlan.zhihu.com/p/109946103

Redis 跳躍表預設允許最大的層數是 32,被原始碼中 ZSKIPLIST_MAXLEVEL 定義,當 Level[0] 有 264 個元素時,才能達到 32 層,所以定義 32 完全夠用了。

 

為什麼用跳錶

紅黑樹真好,但是跳錶真香。

為什麼跳錶香?

  • 好實現

  • 索引便利,可以快速找到區間中批量資料,更方便做批操作。 zrangebyscore

至於為啥說好實現、好做批量操作,自己手寫個跳錶直觀感受一下就好了呀。

為什麼不用跳錶

  • 如果數量級少,索引級數小的情況下,隨機構建插入節點存在偶發的低效。

  • 高度擴容後順序大量插入資料會導致擴容前資料索引不會被高階索引cover

 

為啥 redis 使用跳錶(skiplist)而不是使用 red-black? 跳錶插入效率比紅黑色高,而且要做執行緒安全處理也比紅黑色簡單

點選展開內容

There are a few reasons:

1) They are not very memory intensive. It's up to you basically. Changing parameters about the probability of a node to have a given number of levels will make then less memory intensive than btrees.

2) A sorted set is often target of many ZRANGE or ZREVRANGE operations, that is, traversing the skip list as a linked list. With this operation the cache locality of skip lists is at least as good as with other kind of balanced trees.

3) They are simpler to implement, debug, and so forth. For instance thanks to the skip list simplicity I received a patch (already in Redis master) with augmented skip lists implementing ZRANK in O(log(N)). It required little changes to the code.

About the Append Only durability & speed, I don't think it is a good idea to optimize Redis at cost of more code and more complexity for a use case that IMHO should be rare for the Redis target (fsync() at every command). Almost no one is using this feature even with ACID SQL databases, as the performance hint is big anyway.

About threads: our experience shows that Redis is mostly I/O bound. I'm using threads to serve things from Virtual Memory. The long term solution to exploit all the cores, assuming your link is so fast that you can saturate a single core, is running multiple instances of Redis (no locks, almost fully scalable linearly with number of cores), and using the "Redis Cluster" solution that I plan to develop in the future.

 

有幾個原因:

1) 它們不是很佔用記憶體。基本上由你決定。更改關於節點具有給定級別數的概率的引數將使其比btree佔用更少的記憶體。

2) 排序集通常是許多ZRANGE或ZREVRANGE操作的目標,即作為連結串列遍歷跳過列表。通過此操作,跳過列表的快取區域性性至少與其他型別的平衡樹一樣好。

3) 它們更易於實現、除錯等。例如,由於跳過列表的簡單性,我收到了一個補丁(已經在Redis master中),其中包含在O(log(N))中實現ZRANK的擴充套件跳過列表。它只需要對程式碼進行少量更改。

關於僅附加的耐用性和速度,我不認為以更多程式碼和更復雜的用例為代價優化Redis是一個好主意,因為對於Redis目標來說IMHO應該是罕見的(每個命令都使用fsync()。幾乎沒有人使用這個特性,即使是在ACID-SQL資料庫中,因為效能提示無論如何都很重要。

關於執行緒:我們的經驗表明Redis主要是I/O繫結的。我正在使用執行緒從虛擬記憶體提供服務。利用所有核心的長期解決方案是,假設您的連結速度如此之快,您可以使單個核心飽和,則執行多個Redis例項(無鎖,幾乎完全可隨核心數線性擴充套件),並使用我計劃在未來開發的“Redis群集”解決方案。