1.概念分析
LRU(Least Recently Used),即最近最少使用.怎么理解這個概念呢?我一開始見到這個概念的時候,以為"最近","最少"都是修飾使用的(從中文解釋中可以看出),不過這種理解是錯誤的,最近是修飾最少的,故應該理解為"最近這段時間最少訪問的,最少使用".
這樣理解是不是更清晰一些呢?也就是說,LRU這種算法是會將近期最少使用的數據淘汰掉.這樣說的話,LRU淘汰算法似乎是將最近次數上使用最少的數據淘汰[1],其實不然,或者說理解的不確切,更准確地說,LRU算法是將近期最不會訪問的數據淘汰掉[2](請注意[1]和[2]的不同,[1]處注重了次數上的比較,[2]處卻沒有這層意義).它的核心思想是"如果數據最近被訪問過,那么將來被訪問的概率也很高".反過來說,"如果數據最近這段時間一直都沒有訪問,那么將來被訪問的概率也會很低".Well,我知道這兩句都是偽命題,就好像說一個人最近一直倒霉,那么他一輩子都會倒霉.不過,LRU就是基於這種思想來的.如果一個指導思想本身就有很多問題,那么在指導現實行為時就更加荒唐了(似乎有點形而上學的意味了...).
因此,我們在這里可以說,LRU是荒唐的,是簡單粗暴的,是片面的.打住,似乎變成了LRU的批斗會了.
--那么LRU就一無是處了?
--不是的.LRU算法的優點在於簡單,而且也可以解決一些實際問題.只不過沒那么精確而已,很多時候LRU算法也會有不少冤假錯案,本來不該剔除的數據就白白的犧牲掉了.但是我們還是要正式LRU的優點.
下面就講解LRU的算法實現.
2.原理
我畫了一個LRU淘汰算法的過程圖:
下面簡單講解一下(需要在這里說明一下,LRU一般采用鏈表方式實現,便於快速移動數據位置,雖然圖中使用似乎是數組方式):
- 一開始,緩存池是空的,緩存池中插入數據時不用擔心容量不足的事情.因此這個過程就是類似隊列的FIFO(但不止這些);
- 在第5步將E插入到緩存池中后,緩存池已經滿了(當然實際應用中不會讓到達緩存池的尺寸,一般到70%左右就要考慮淘汰機制了);
- 當第6步將E插入緩存池的時候,發現緩存池已經滿了,LRU會將最早加入到緩存池的數據淘汰掉(A,實在不要意思啊);
- 第7步,從緩存池中訪問C,C被訪問,從時間點上是最近最近訪問的,將C移動到鏈表的頭部(C僥幸暫時遠離被淘汰的邊緣);
- 第8步,將G插入緩存池中,G處於鏈表頭部,B不幸被淘汰.
大致的過程就是這樣,關於淘汰機制只是后面的三步中會用到,畫出前面六步的過程只是說明,LRU插入元素的方式.在這個圖中,我想大家應該可以明白為什么使用鏈表,而不使用數組(鏈表的插入和刪除的時間復雜度都是O(1)).
3.優劣分析
【命中率】
命中率較高,不過偶發性的情況對LRU的命中影響很大,同時也會引入很多數據污染(比如很長時間只訪問一次的數據,在后期的文章中會涉及到這一話題,會有改進的方案).
【復雜度】
實現起來較為簡單.
【存儲成本】
幾乎沒有空間上浪費.
【缺陷】
僅僅從最近使用時間上考慮淘汰算法,沒有考慮緩存單元的使用頻率,可能會淘汰一些仍有價值的單元.
4.實現
暫時略,以后會采用偽代碼和java語言的方式做簡單的實現.
最后,如有哪里不正確的地方,請多多指教. 后續會將其他緩存淘汰算法一一介紹,敬請期待.
相關文章: