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 { }
}

 

最新文章

  1. [Cordova] 手机网页里的1px
  2. 查询Oracle正在执行和执行过的SQL语句
  3. 从其它系统登录到SharePoint 2010系统的单点登录
  4. MongoDB 备份(mongodump)恢复(mongorerstore) 导出 (Mongoexport) 导入( Mongoimport)
  5. Myeclipse SVN错误 443
  6. git 配置用户名和邮箱
  7. Python3.5入门学习记录-条件控制
  8. 快速构建Windows 8风格应用30-应用生命周期管理
  9. PHP三维数组拼装
  10. 【BZOJ】1015 [JSOI2008]星球大战starwar(并查集+离线处理)
  11. java常用类————Date类
  12. ES6(类)
  13. R12中注册客户化应用为多组织应用
  14. Python学习笔记 - 迭代Iteration
  15. FatMouse&#39; Trade -HZNU寒假集训
  16. 1024程序员节宅男节日快乐 -- JAVA快速开发平台,JEECG 3.8宅男优化版本发布
  17. Oracle数据库用户锁定原因以及处理方式(ORA-28000)
  18. Mycat节点扩缩容及高可用集群方案
  19. Linux 常用命令——which, whereis, locate, find
  20. 网上搜到的权限系统demo

热门文章

  1. Codeforce 141A - Amusing Joke (sort)
  2. Ubuntu中chrome浏览器安装、卸载
  3. 在Unity5中使用C#脚本实现UI的下滑、变色、渐隐渐现效果
  4. KMP小扩展,找出子串在主串中出现的所有位置
  5. php server整理
  6. js中迭代方法
  7. SVN merge(合并) 时看不到以前的已经合并过的记录的标识
  8. Codeforces Round #621 (Div. 1 + Div. 2)E(二分查找,枚举分界点,容斥原理)
  9. Spring Boot的27个注解【核心】
  10. 【模板】裸SPFA