zoukankan      html  css  js  c++  java
  • 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("开始扫描
    ")
    		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 {
    
    	}
    }
    

     

  • 相关阅读:
    (转载)Android mac 真机调试
    Google Map SDK for iOS
    autolayout under navigation bar
    Xamarin Mono For Android、Monotouch 安装
    不错的ORM调试查看SQL插件
    在Windows 8.1系统上配置免安装版mysql-5.6.21-winx64
    VS2013 EF6连接MySql
    安卓离线SDK Windows版 资源包下载地址全集
    WndProc函数参数列表
    反射创建对象
  • 原文地址:https://www.cnblogs.com/-wenli/p/12373843.html
Copyright © 2011-2022 走看看