Cache類型
Cache封裝了一個cache類型,cache類型的參數解析:
1.defaultExpiration time.Duration
每個鍵值的默認過期時間。
2.items map[string]Item
map類型。
3.mu sync.RWMutex
map類型的讀寫鎖。
4.janitor *janitor
監控map中鍵值是否過期,定期刪除map中過期的鍵值。
5.onEvicted func(string, interface{})
用戶定義,可以對已經被刪除鍵值做二次操作。
type Cache struct {
*cache
// If this is confusing, see the comment at the bottom of New()
}
type cache struct {
defaultExpiration time.Duration
items map[string]Item
mu sync.RWMutex
onEvicted func(string, interface{})
janitor *janitor
}
Item類型如下,定義map中key對應的每個值:
type Item struct {
Object interface{}
Expiration int64
//一個參數是Object存儲value,另一個參數Expiration 為過期時間。
}
初始化Cache
New(defaultExpiration, cleanupInterval time.Duration) *Cache {}:返回*Cache類型。
//創建一個緩存庫,這個緩存庫默認每個鍵值的過期時間為五分鍾,每十分鍾清理一次 c := cache.New(5*time.Minute, 10*time.Minute)
newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache{}:先創建map,繼續往下調用。
func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
items := make(map[string]Item)
return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
}
func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
//de為每個鍵值對的默認過期時間,ci為緩存池的定期掃描時間,m為緩存map:make(map[string]Item)
//初始化cache
c := newCache(de, m)
//初始化Cache
C := &Cache{c}
if ci > 0 {
//監控map:創建監控器及定時器
runJanitor(c, ci)
//給C綁定方法,當垃圾回收的時候執行
runtime.SetFinalizer(C, stopJanitor)
}
return C
}
newCache(de time.Duration, m map[string]Item) *cache :初始化cache:可以這里定義cache的屬性。
func newCache(de time.Duration, m map[string]Item) *cache {
if de == 0 {
de = -1
}
c := &cache{
defaultExpiration: de,
items: m,
onEvicted: func(s string, i interface{}) {
println("鍵值被刪除了,可以做這里做二次操做")
},
}
return c
}
監控器及定時器
監控器有兩個屬性,一個是定時掃描是否過期的時間,第二個為通知監控器關閉的信道。
type janitor struct {
Interval time.Duration
stop chan bool
}
創建監控器及使用協程啟動。
func runJanitor(c *cache, ci time.Duration) {
j := &janitor{
Interval: ci,
stop: make(chan bool),
}
c.janitor = j
go j.Run(c)
}
運行監控器,創建了一個定時器,使用select監控定時器信道和關閉信道。
func (j *janitor) Run(c *cache) {
//創建定時器
ticker := time.NewTicker(j.Interval)
for {
select {
case <-ticker.C://當定時器每次到達設置的時間時就會向管道發送消息,此時檢查map中的鍵值是否過期
c.DeleteExpired()
case <-j.stop: //監視器退出信道,
ticker.Stop()
return
}
}
}
添加記錄
c.Set("foo", "bar", cache.DefaultExpiration)
const ( NoExpiration time.Duration = -1 DefaultExpiration time.Duration = 0 )
func (c *cache) Set(k string, x interface{}, d time.Duration) {
var e int64
if d == DefaultExpiration {
d = c.defaultExpiration
}
if d > 0 {
//這里很重要,如果設置緩存時間大於0,則在現在時間上加上設置的緩存時間
e = time.Now().Add(d).UnixNano()
}
c.mu.Lock()
c.items[k] = Item{
Object: x,
Expiration: e,
}
c.mu.Unlock()
}
刪除記錄
c.Delete("foo")
func (c *cache) Delete(k string) {
c.mu.Lock()
//如果有OnEvicted方法,則返回k及true,如果沒有,則返回空和false
v, evicted := c.delete(k)
c.mu.Unlock()
//evivted為真,則表示用戶自定義了OnEvicted方法,對刪的鍵值做刪除后的操作
if evicted {
c.onEvicted(k, v)
}
}
func (c *cache) delete(k string) (interface{}, bool) {
if c.onEvicted != nil {
//如果存在OnEvicted方法,則執行,
if v, found := c.items[k]; found {
delete(c.items, k)
return v.Object, true
}
}
//如果不存在OnEvicted方法
delete(c.items, k)
return nil, false
}
定期刪除
// Delete all expired items from the cache.
func (c *cache) DeleteExpired() {
var evictedItems []keyAndValue
//現在時間戳
now := time.Now().UnixNano()
//map加互斥鎖
c.mu.Lock()
for k, v := range c.items {
// "Inlining" of expired
//檢測map
if v.Expiration > 0 && now > v.Expiration {
//超時則刪除
ov, evicted := c.delete(k)
//err為真則會記錄刪除的鍵值,也表示onEvicted方法存在,對刪除的key-value做二次操作
if evicted {
evictedItems = append(evictedItems, keyAndValue{k, ov})
}
}
}
c.mu.Unlock()//解互斥鎖
//c.onEvicted為函數類型,初始緩存map的時候賦值:func(string, interface{})
//替換這個函數:func (c *cache) OnEvicted(f func(string, interface{}))
//可以對已經刪除的key—value做二次操作,用戶定義
for _, v := range evictedItems {
c.onEvicted(v.key, v.value)
}
}
go實現定時器模板:定時循環執行
package main
import "time"
type janitor struct {
Interval time.Duration
stop chan bool
}
func (j *janitor) Run() {
//創建定時器
ticker := time.NewTicker(j.Interval)
for {
select {
case <-ticker.C://當定時器每次到達設置的時間時就會向管道發送消息,此時檢查map中的鍵值是否過期
print("開始掃描\n")
case <-j.stop: //監視器退出信道,
ticker.Stop()
close(j.stop)
return
}
}
}
func stopJanitor(j *janitor) {
j.stop <- true
}
func runJanitor(ci time.Duration) {
j := &janitor{
Interval: ci,
stop: make(chan bool),
}
go j.Run()
}
func main(){
runJanitor(time.Second)
select {
}
}
