一、概述
我們今天開始第一部分“golang技能提升”。這一塊我計劃分析3個項目,一個是很流行的golang源碼閱讀入門項目cache2go,接著是非常流行的memcache的go語言版groupcache,最後是docker項目中分出來的核心組件之一containerd,通過這3個項目的源碼全解析來達到golang能力上一個台階的目的。
在本系列教程的學習過程中,我希望你能夠做到如下要求:如果你是一個go語言新手,在看下面的程式碼分析過程中你肯定會遇到一些自己陌生的編碼方式、陌生的知識點,這個過程中我希望你遇到一個點掌握一個點,比如看到下面的代碼用到了鎖,就去找各種資料把鎖相關的知識點學了。看到回呼函數,就思考一下人家為什麼這些地方都使用回呼函數,有什麼好處。這樣在看完這個項目源碼分析後,你就能學到一部分知識模組
二、cache2go是什麼
這是一個在github上開源的項目,原作者這樣介紹:
Concurrency-safe golang caching library with expiration capabilities.
看懂了嗎?簡單說就是有心跳機制的並發安全的go語言緩衝庫。ok,下面我們要分析的這個項目是一個緩衝庫,並且有2大特性,並發安全和心跳機制!
三、項目結構
項目目錄結構如所示,可以看到功能實現相關源碼檔案只有3個:
cache.go
cacheitem.go
cachetable.go
四、關鍵資料結構
項目中只涉及到2個複雜的資料類型,分別是:
含義和字面意義一致,一個是緩衝表,一個是緩衝表中的條目。下面分別看一下這2個結構是怎麼定義的。
1、CacheItem
CacheItem類型是用來表示一個單獨的緩衝條目,源碼如下所示,每個欄位都很清晰易懂,注釋稍長的屬性已經中文標註。
1// CacheItem is an individual cache item 2// Parameter data contains the user-set value in the cache. 3type CacheItem struct { 4 sync.RWMutex 5 6 // The item's key. 7 key interface{} 8 // The item's data. 9 data interface{}10 //【不被訪問後存活時間】11 // How long will the item live in the cache when not being accessed/kept alive.12 lifeSpan time.Duration1314 // Creation timestamp.15 createdOn time.Time16 // Last access timestamp.17 accessedOn time.Time18 // How often the item was accessed.19 accessCount int6420 //【被刪除時觸發的回調方法】21 // Callback method triggered right before removing the item from the cache22 aboutToExpire func(key interface{})23}
2、CacheTable
CacheTable描述了緩衝中的一個表項,裡面的items屬性就是上面講到的CacheItem類型執行個體。這裡除了常規屬性外還有若干函數類型的屬性,源碼如下所示(最後幾行顯示樣式好像抽筋了~):
1// CacheTable is a table within the cache 2type CacheTable struct { 3 sync.RWMutex 4 5 // The table's name. 6 name string 7 // All cached items. 8 //【一個表中的所有條目都存在這個map裡,map的key是任意類型,值是CacheItem指標類型】 9 items map[interface{}]*CacheItem1011 // Timer responsible for triggering cleanup.12 //【負責觸發清除操作的計時器】13 cleanupTimer *time.Timer14 // Current timer duration.15 //【清除操作觸發的時間間隔】16 cleanupInterval time.Duration1718 // The logger used for this table.19 logger *log.Logger2021 // Callback method triggered when trying to load a non-existing key.22 //【需要提取一個不存在的key時觸發的回呼函數】23 loadData func(key interface{}, args ...interface{}) *CacheItem24 // Callback method triggered when adding a new item to the cache.25 //【增加一個緩衝條目時觸發的回呼函數】26 addedItem func(item *CacheItem)27 // Callback method triggered before deleting an item from the cache.28 //【刪除前觸發的回呼函數】29 aboutToDeleteItem func(item *CacheItem)30}
如上所示,cache2go的核心資料結構很簡潔,應該比較容易理解。當然沒有完全理解每個欄位這樣定義的原因也別急,看完下面的代碼邏輯後反過來再看資料結構,肯定就明白每個欄位的作用了。
五、代碼邏輯
我們的思路是從下往上分析代碼,什麼意思呢?就是說先看和item相關的操作,再看包含item的table相關的代碼,最後看操作table的cache層級的邏輯。所以下面我們要先看cacheitem.go的代碼,接著分析cachetable.go,然後看cache.go,最後看3個檔案中的源碼互相間關聯是什麼,最後看example,也就是cache怎麼玩~
1、cacheitem.go
如,這個源碼檔案中只包含了一個類型CacheItem和一個函數NewCacheItem()的定義。CacheItem有哪些屬性前面已經看過了,下面先看NewCacheItem()函數:
1// NewCacheItem returns a newly created CacheItem. 2// Parameter key is the item's cache-key. 3// Parameter lifeSpan determines after which time period without an access the item 4// will get removed from the cache. 5// Parameter data is the item's value. 6func NewCacheItem(key interface{}, lifeSpan time.Duration, data interface{}) *CacheItem { 7 t := time.Now() 8 return &CacheItem{ 9 key: key,10 lifeSpan: lifeSpan,11 createdOn: t,12 accessedOn: t,13 accessCount: 0,14 aboutToExpire: nil,15 data: data,16 }17}
cacheitem.go中除了CacheItem類型的定義,NewCacheItem()函數的定義外,還有一個部分就是CacheItem的方法定義,一共8個
源碼看起來行數不少,內容其實很簡單,主要是元素擷取操作,這裡需要留意讀寫操作都是加了相應的讀寫鎖的,還記得開頭提到的cache2go是一個並發安全的程式嗎?並發安全就體現在這些地方。下面最複雜的是最後一個回呼函數的設定,這個方法的形參是f func(interface{}),也就是說形參名為f,形參類型是func(interface{}),這是一個函數類型,這個函數類型的參數是一個interface{},也就是空介面,因為任意類型都可以被認為實現了空介面,所以這裡可以接收任意類型的實參。也就是說f的類型是一個可以接收任意型別參數的函數類型。有點繞,需要靜下心來理解一下哦~
源碼如下:
1// KeepAlive marks an item to be kept for another expireDuration period. 2//【將accessedOn更新為目前時間】 3func (item *CacheItem) KeepAlive() { 4 item.Lock() 5 defer item.Unlock() 6 item.accessedOn = time.Now() 7 item.accessCount++ 8} 910// LifeSpan returns this item's expiration duration.11func (item *CacheItem) LifeSpan() time.Duration {12 // immutable13 return item.lifeSpan14}1516// AccessedOn returns when this item was last accessed.17func (item *CacheItem) AccessedOn() time.Time {18 item.RLock()19 defer item.RUnlock()20 return item.accessedOn21}2223// CreatedOn returns when this item was added to the cache.24func (item *CacheItem) CreatedOn() time.Time {25 // immutable26 return item.createdOn27}2829// AccessCount returns how often this item has been accessed.30func (item *CacheItem) AccessCount() int64 {31 item.RLock()32 defer item.RUnlock()33 return item.accessCount34}3536// Key returns the key of this cached item.37func (item *CacheItem) Key() interface{} {38 // immutable39 return item.key40}4142// Data returns the value of this cached item.43func (item *CacheItem) Data() interface{} {44 // immutable45 return item.data46}4748// SetAboutToExpireCallback configures a callback, which will be called right49// before the item is about to be removed from the cache.50//【設定回呼函數,當一個item被移除的時候這個函數會被調用】51func (item *CacheItem) SetAboutToExpireCallback(f func(interface{})) {52 item.Lock()53 defer item.Unlock()54 item.aboutToExpire = f55}
到這裡就看完這個源檔案了,是不是很輕鬆呢~
上面的一堆方法功能都還是很直觀的,今天我們先看到這裡,下一講繼續分析cachetable相關代碼。
191 次點擊