go key-value緩存go-cache實現


 

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 {

	}
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM