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实现的更多相关文章

  1. [Java 缓存] Java Cache之 DCache的简单应用.

    前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...

  2. [Java 缓存] Java Cache之 Guava Cache的简单应用.

    前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...

  3. 缓存篇(Cache)~大话开篇

    回到占占推荐博客索引 闲话杂淡 想写这篇文章很久了,但总是感觉内功还不太够,总觉得,要写这种编程领域里的心法(内功)的文章,需要有足够的实践,需要对具体领域非常了解,才能写出来.如今,感觉自己有写这种 ...

  4. 使用JDK自带缓存(Cache)实现Cookie自动登陆

    自定义一个缓存类AdminCache package jw.admin.common; import jw.base.entity.Admin; import sun.security.util.Ca ...

  5. ASP.NET缓存中Cache过期的三种策略

    原文:ASP.NET缓存中Cache过期的三种策略 我们在页面上添加三个按钮并双击按钮创建事件处理方法,三个按钮使用不同的过期策略添加ASP.NET缓存. <asp:Button ID=&quo ...

  6. 分布式缓存HttpRuntime.cache应用到单点登陆中_优化登陆

    以前的设计方案,是我们在数据库中放一个表,用作存储验证登陆成功的用户,并且生成用户TOKEN(令牌) 分布式缓存+集群的解决方案图: 相应的代码: DE层中配置文件: receiveTimeout=& ...

  7. yii中缓存(cache)详解

    缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: 1 ...

  8. yii中缓存(cache)详解 - 彼岸あ年華ツ

    缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成 这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: ...

  9. spring boot redis 缓存(cache)集成

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  10. 缓存篇(Cache)~第三回 HttpModule实现网页的文件级缓存

    返回目录 再写完缓存篇第一回之后,得到了很多朋友的好评和来信,所以,决定加快步伐,尽快把剩下的文章写完,本篇是第三回,主要介绍使用HttpModule实现的文件级缓存,在看本文之前,大家需要限度Htt ...

随机推荐

  1. Alice and Hairdresser

    Alice's hair is growing by leaps and bounds. Maybe the cause of it is the excess of vitamins, or may ...

  2. vue配置开发,测试,生产环境api

    npm run build 调用开发环境接口,打包开发环境npm run build:test 调用测试环境接口,打包测试环境npm run build:prod 调用生产环境接口,打包生产环境 vu ...

  3. vue formatter element表格处理数据

    formatter 指定一个vue methods 方法 作用:对从数据库中取出的数据进行处理后展示. <el-table-column prop="partner1" // ...

  4. 剖析Javascript中forEach()底层原理,如何重写forEach()

    我们平时用的forEach()一般是这样用的 var myArr = [1,5,8] myArr.forEach((v,i)=>{ console.log(v,i) })//运行后是这样的1 0 ...

  5. PyQt5+Eric6开发的一个使用菜单栏、工具栏和状态栏的示例

    前言 在做一个数据分析的桌面端程序遇到一些问题,这里简单整理下,分享出来供使用者参考. 1.网上查使用PyQt5工具栏的示例,发现很多只是一个简单的退出功能,如果有几个按钮如何处理?如何区分点击的究竟 ...

  6. 【Unity|C#】基础篇(9)——匿名函数 / Lambda表达式

    [学习资料] <C#图解教程>(第13章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...

  7. 使用在react hooks+antd ListView简单实现移动端长列表功能

    import React, { useState, useEffect } from "react" import { ListView } from "antd-mob ...

  8. dmesg用法

    百科概念:dmesg是一种程序,用于检测和控制内核环缓冲.程序用来帮助用户了解系统的启动信息. 解释:dmesg命令显示linux内核的环形缓冲区信息,我们可以从中获得诸如系统架构.cpu.挂载的硬件 ...

  9. 网络流EK算法模板

    \(EK\)算法的思想就是每一次找一条增广路进行增广. 注意几个点: 存图时\(head\)数组要设为\(-1\). 存图的代码是这样的: inline void add(int u, int v, ...

  10. 在github网站上更新fork的repo

    打开fork的repo. 点击Pull request, 这里会跳转到一个页面提示There isn’t anything to compare. 点击switching the base,将orig ...