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 { }
}
go key-value缓存go-cache实现的更多相关文章
- [Java 缓存] Java Cache之 DCache的简单应用.
前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...
- [Java 缓存] Java Cache之 Guava Cache的简单应用.
前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...
- 缓存篇(Cache)~大话开篇
回到占占推荐博客索引 闲话杂淡 想写这篇文章很久了,但总是感觉内功还不太够,总觉得,要写这种编程领域里的心法(内功)的文章,需要有足够的实践,需要对具体领域非常了解,才能写出来.如今,感觉自己有写这种 ...
- 使用JDK自带缓存(Cache)实现Cookie自动登陆
自定义一个缓存类AdminCache package jw.admin.common; import jw.base.entity.Admin; import sun.security.util.Ca ...
- ASP.NET缓存中Cache过期的三种策略
原文:ASP.NET缓存中Cache过期的三种策略 我们在页面上添加三个按钮并双击按钮创建事件处理方法,三个按钮使用不同的过期策略添加ASP.NET缓存. <asp:Button ID=&quo ...
- 分布式缓存HttpRuntime.cache应用到单点登陆中_优化登陆
以前的设计方案,是我们在数据库中放一个表,用作存储验证登陆成功的用户,并且生成用户TOKEN(令牌) 分布式缓存+集群的解决方案图: 相应的代码: DE层中配置文件: receiveTimeout=& ...
- yii中缓存(cache)详解
缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: 1 ...
- yii中缓存(cache)详解 - 彼岸あ年華ツ
缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成 这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: ...
- spring boot redis 缓存(cache)集成
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- 缓存篇(Cache)~第三回 HttpModule实现网页的文件级缓存
返回目录 再写完缓存篇第一回之后,得到了很多朋友的好评和来信,所以,决定加快步伐,尽快把剩下的文章写完,本篇是第三回,主要介绍使用HttpModule实现的文件级缓存,在看本文之前,大家需要限度Htt ...
随机推荐
- 我的第一个Maven Helloworld
使用MAVEN创建项目可以有两种方式进行创建,第一种,使用mvn命令创建Maven项目,第二种,使用eclipse创建Maven项目. 在创建Maven项目之前,我们需要安装maven,并和配置JDK ...
- mybatis一级缓存和二级缓存(三)
缓存详细介绍,结果集展示 https://blog.csdn.net/u013036274/article/details/55815104 配置信息 http://www.pianshen.co ...
- python dataframe筛选列表的值转为list【常用】
网上方法参差不齐,无注释解释不好秒懂,没有自己想要的,故自己试验一番~ 1. 筛选列表中,当b列中为’1’时,所有c的值,然后转为list 2 .筛选列表中,当a列中为'one',b列为'1'时,所有 ...
- JS全选按钮练习
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...
- Web安全测试学习笔记 - 文件包含
基础知识 文件包含指的是一个文件动态引用另一个文件,这是一种非常灵活的动态调用方式.有点类似Java引用jar包,但区别在于jar包引用后一般是固定不变的(一般不能动态改变所引用的jar包名称),而文 ...
- mysql行级锁 select for update
mysql行级锁 select for update 1.属于行级锁 2.where条件后需要写出明确的索引条件(如果有多个条件,可以建立联合索引) 3.如果其所在的事务提交或者回滚后,或者更新该条数 ...
- JUC-JUC是什么?
一.JUC是什么? java.util.concurrent在并发编程中使用的工具类 进程/线程回顾 1.进程/线程是什么? 进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是 ...
- C++-hihoCode1545-小Hi和小Ho的对弈游戏[树上Nim]
#include <set> #include <map> #include <cmath> #include <queue> #include < ...
- 浅析State-Thread
State-Thread(以下简称st),是一个由C语言编写的小巧.简洁却高效的开源协程库.这个库基于单线程运作.不强制占用用户线程,给予了开发者最大程度的轻量级和较低的侵入性.本篇文章中,网易云信音 ...
- [HNOI2014] 道路堵塞 - 最短路,线段树
对不起对不起,辣鸡蒟蒻又来用核弹打蚊子了 完全ignore了题目给出的最短路,手工搞出一个最短路,发现对答案没什么影响 所以干脆转化为经典问题:每次询问删掉一条边后的最短路 如果删掉的是非最短路边,那 ...