這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
9.go開源groupcache項目筆記——lru代碼
LRU是LeastRecently Used 近期最少使用演算法。
記憶體管理的一種頁面置換演算法,對於在記憶體中但又不用的資料區塊(記憶體塊)叫做LRU,作業系統會根據哪些資料屬於LRU而將其移出記憶體而騰出空間來載入另外的資料。
LRU用於實現LRU 的cache.
1 LRU檔案
1.1 Cache結構體
先定義了一個cache結構體。
MaxEntries int是最大CACHE容量。
OnEvicted func(key Key, value interface{}) 是一個可選的回呼函數,當一個ITEM從CACHE中清除的時候調用。
ll *list.List是一個鏈表的指標
cache map[interface{}]*list.Element 是一個map類型,為列表中元素的指標。
PS:interface{},在Go中它可以指向任意對象,也就任意對象都是先這個介面,你可以把它看成Java/C#中的Object, C/C++中的void*。list.Element其指向的類型是entry類型
1.2 其他定義
定義Key為介面,表示Key可以為任何值。
定義entry為結構體,包含key和value。其中key為Key類型,value為介面。
2 New函數
返回一個Cache結構體。
入參為一個整數,就是CACHE支援的最大容量,如果為0表示無上線
建立一個新的鏈表。
3 Add函數
入參為key Key,value interface{}.
首先判斷當前Cache是否為nil,如果為nil則先new一個出來。
如果已經存在該key則將該元素指標移到列表前面,並將對應的值進行更新,代碼如:ee.Value.(*entry).value= value 然後。
如果該key不存在,則將新的值添加到列表最前面,同時加入到Cache結構體中cache,接著判斷是否超過了CACHE的最大數量,超過則調用RemoveOldest來刪除最舊的entry。
4 Get函數
入參為key類型為Key。返回value和是否ok.
如果不存在緩衝則直接換回。
如果存在就意味著命中,將元素指標移到列表前面,然後返回元素和TRUE
5 Remove函數
如果緩衝不存在,則直接返回。
如果存在,調用removeElement移除指標。
6 RemoveOldest函數
如果緩衝不存在,則直接返回。
如果有緩衝則調用removeElement從列表的後端開始刪除。
7 removeElement函數
入參為列表指標。
直接調用列表的Remove函數刪除指標。
然後使用delete命令從map(c.cache)中刪除對應的項
如果有回呼函數則調用回呼函數。
8 Len函數
返回列表長度,如果Cache結構體中的map為nil直接返回0.
PS:Go中實現一個類的成員方法,在func之後加類,在Go中介面的實現並不是和Java中那樣子,而是只要某個類只要實現了某個介面的所有方法,即可認為該類實現了該介面。
Go中開頭字母大寫的變數名,類名,方法名表示對外可知,小寫開頭的表示對外不暴露。另外類實這種代碼ele.Value.(*entry).value,其中(*entry)表示將Value轉成*entry類型訪問。
9 LRU_TESET
用於測試lru。
定義了兩個結構體simpleStruct,complexStruct
然後定義一個變數getTests,如下
vargetTests=[]struct{
name string
keyToAdd interface{}
keyToGet interface{}
expectedOkbool
}{
{"string_hit","myKey","myKey",true},
{"string_miss","myKey","nonsense",false},
{"simple_struct_hit",simpleStruct{1,"two"},simpleStruct{1,"two"},true},
{"simeple_struct_miss",simpleStruct{1,"two"},simpleStruct{0,"noway"},false},
{"complex_struct_hit",complexStruct{1,simpleStruct{2,"three"}},
complexStruct{1,simpleStruct{2,"three"}},true},
}
主要是兩個用例如下
9.1 TestGet
從變數getTests迴圈擷取,先調用New建立一個lru.
然後根據getTests. keyToAdd來增加緩衝。每個索引值都為1234.
然後在增加完後進行擷取索引值是否滿足條件。
迴圈結束後測試也結束。
9.2 TestRemove
先增加一個lru。
然後增加一個索引值,測試OK
然後將索引值刪除。檢查刪除是否成功。
9.3 測試結果
=== RUN TestGet
--- PASS: TestGet (0.00s)
=== RUN TestRemove
--- PASS: TestRemove(0.00s)
PASS
ok test 0.135s