沉浸式go-cache源码阅读!

这篇具有很好参考价值的文章主要介绍了沉浸式go-cache源码阅读!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好,我是豆小匠。

这期来阅读go-cache的源码,了解本地缓存的实现方式,同时掌握一些阅读源码的技巧~


1. 源码获取

git clone https://github.com/patrickmn/go-cache.git

用Goland打开可以看到真正实现功能的也就两个go文件,cache.go 1162行,sharded.go 193行,共1355行,用来作为源码阅读的练手素材是非常合适的。

沉浸式go-cache源码阅读!,技术学习,golang,开发语言,后端

通过README.md文件,可以了解这个包的使用方法:

import (
	"fmt"
	"github.com/patrickmn/go-cache"
	"time"
)

func main() {
  // 创建一个缓存对象,默认过期时间5分钟,每10分钟清理一次缓存
	c := cache.New(5*time.Minute, 10*time.Minute)

	// 设置缓存key:foo,value:bar,过期时间是包里定义的一个常量,一会看看具体定义了啥
	c.Set("foo", "bar", cache.DefaultExpiration)
  
	// 获取key为foo的缓存,通过类型断言获取原始的数据
	foo, found := c.Get("foo")
	if found {
		MyFunction(foo.(string))
	}
}

2. 源码阅读

上面我们看到,创建一个缓存实例,需要传入缓存清理的间隔,也就是说缓存的删除不是根据缓存过期时间实时删除的,那怎么处理才能让已过期的缓存在逻辑上失效呢?

带着疑问,开始阅读cache.go文件。

2.1. Cache定义

type Cache struct {
	*cache // 为何套娃,先按下不表
}

type cache struct {
	defaultExpiration time.Duration	// 默认过期时间
	items             map[string]Item // 所有缓存key value,用一个map保存,key是string,value是一个结构体Item
	mu                sync.RWMutex	// 读写锁,可以知道go-cache大概率是并发安全的
	onEvicted         func(string, interface{}) // 这啥,先不管
	janitor           *janitor // 这啥,先不管
}

type Item struct {
	Object     interface{}	// 真正存储的缓存数据
	Expiration int64	// 这个数据的过期时间
}

看完Cache结构体的定义,先有个整体印象,再看它的方法实现~

2.2. Cache初始化

在README.go,我们已经知道,初始化的函数是New(defaultExpiration, cleanupInterval time.Duration),双击shift,输入New,就能找到这个函数。

沉浸式go-cache源码阅读!,技术学习,golang,开发语言,后端

type janitor struct {
	Interval time.Duration	// 清理过期缓存的间隔
	stop     chan bool // 接受停止协程的信号
}

func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
	items := make(map[string]Item)	// 定义缓存容器,会存到cache对象的items
	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items) // 创建一个带有清理协程的Cache对象
}

func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
	c := newCache(de, m) // 生成小写那个cache对象(私有)
	C := &Cache{c}
	if ci > 0 {	// 传入定时删除缓存时间大于0,启动看清理协程
		runJanitor(c, ci)	// 启动清理协程,定时删除过期的cache key
		runtime.SetFinalizer(C, stopJanitor) // 设置C被回收时,执行函数停止清理协程
	}
	return C
}

runtime.SetFinalizer:对象可以关联一个SetFinalizer函数, 当gc检测到unreachable对象有关联的SetFinalizer函数时,会执行关联的SetFinalizer函数, 同时取消关联。 这样当下一次gc的时候,对象重新处于unreachable状态并且没有SetFinalizer关联, 就会被回收。

通过上面源码的阅读,我们可以知道:

  1. 清理过期缓存通过一个清理协程定期清理。
  2. 当Cache不可达时,GC会触发停止janitor协程的函数,下一次GC,Cache和cache(内部cache对象)都会被回收。(如果janitor协程和Cache绑定,Cache对象不会被回收,有内存泄露的风险)
c := cache.New(5*time.Minute, 10*time.Minute)
c = nil	// 这里cache已经不使用了,第一次GC会执行SetFinalizer函数,停掉清理协程,第二次GC则会把Cache和cache对象都回收掉

如果清理协程绑定在Cache对象,因为协程一直在运行,即使在使用者看来c已经设置为nil,cache不再使用,GC也无法回收Cache。

2.3. 缓存失效判断

Cache上是不挂方法的,方法都挂在内部对象cache上。

沉浸式go-cache源码阅读!,技术学习,golang,开发语言,后端

我们先看Get方法:

func (c *cache) Get(k string) (interface{}, bool) {
	c.mu.RLock()	// 加读锁
	item, found := c.items[k]
	if !found {
		c.mu.RUnlock()
		return nil, false
	}
  // 下面这里会判断item里的过期时间,过期时间小于当前时间,则在逻辑上失效,返回nil, false
	if item.Expiration > 0 {	// 如果expiration为0,说明设置的是永不过期
		if time.Now().UnixNano() > item.Expiration {
			c.mu.RUnlock()
			return nil, false
		}
	}
	c.mu.RUnlock()
	return item.Object, true
}

看源码可以很清晰的看到,缓存过期不是通过是否存在key来判断的,而是通过item里存的expiration时间来判断,因此定时清理缓存是为了清理空间。

2.4. 总体梳理

其他方法都非常明确,我们可以挑几个常用的看看实现,最后整理下cache这个类的成员变量和方法,画个图,完事!

沉浸式go-cache源码阅读!,技术学习,golang,开发语言,后端

前面埋的坑:onEvicted 是删除key的回调函数。

另外sharded.go文件是一个实验性的代码,用于缓存分片,目前还没对外暴露。文章来源地址https://www.toymoban.com/news/detail-763287.html

到了这里,关于沉浸式go-cache源码阅读!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Golang项目实战】用Go写一个学生信息管理系统,真的太酷啦| 保姆级详解,附源码——建议收藏

    博主简介: 努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:数据结构、Go,Java等相关知识。 博主主页: @是瑶瑶子啦 所属专栏: Go语言核心编程 近期目标: 写好专栏的每一篇文章 学习了Go的基础语法知识,如何巩固和提升呢?跟着瑶瑶子写一个

    2024年02月02日
    浏览(43)
  • 学习如何在VS Code中创建一个Golang/Go项目,并运行一个简单的Golang程序

     学习如何在VS Code中创建一个Golang项目,并运行一个简单的Golang程序。 在VS Code 手动输入命令创建一个Golang项目 在VS Code 不输入命令创建一个Golang项目 1. 在VS Code 手动输入命令创建一个Golang项目 步骤1:在VS Code中创建一个新文件夹,用于存放Golang项目文件。 步骤2:打开VS

    2024年02月14日
    浏览(47)
  • 【Golang】一篇文章带你快速了解Go语言&为什么你要学习Go语言

    目录 1. 为什么互联网世界需要Go语言 1.1 硬件限制:摩尔定律已然失效  1.2 Go语言为并发而生 1.3 Go性能强悍 1.4 Go语言简单易学 1.4.1 语法简洁 1.4.2 代码风格统一 1.4.3开发效率高  2.Go语言的诞生与发展 2.1什么是Go语言   2.2 Go语言的诞生 2.3 Go Gopher——Go语言的吉祥物 3. 为什么

    2024年02月04日
    浏览(48)
  • 是时候回答【我为什么要学习 Go 语言(golang)】这个问题了

    想必每个人在学习新事物之前,都会扪心自问:“我为什么要学习它呢?” 正如我们读 四大名著 一般,也只有在您读过了 四大名著 后,再细看中国几千年历史不就是 天下大势合久必分,分久必合 ,再者,便是与友数人相聚,席间您述说您通勤时所遇到有意思的事了,而您

    2023年04月09日
    浏览(39)
  • 100天精通Golang(基础入门篇)——第5天: Go语言中的数据类型学习

    🌷 博主 libin9iOak带您 Go to Golang Language.✨ 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批

    2024年02月08日
    浏览(36)
  • 【Go学习】macOS+IDEA运行golang项目,报command-line-arguments,undefined

    1、写在前面的话:idea如何配置golang,自行百度 2、送福利:国内好用的ChatGpt有很多,比如:天工、文心一言、讯飞星火、通义万相等 问题1:通过idea的terminal执行go test报错 这个问题就是当前目录没有go.mod文件,直接用go命令生成一个即可(example.com/m 可以随便自定义,比如:

    2024年01月18日
    浏览(38)
  • 分享一个项目:`learning_go_plan9_assembly`, 学习 golang plan9 汇编

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 近期在学习 golang plan9 汇编,总算基本做到了手写汇编,并整理了很多笔记。 plan9 汇编的资料少,难学,难用。可能也有想学习汇编的人会遇到与我一样的问题。 于是把

    2024年02月06日
    浏览(41)
  • 3D与沉浸式技术,如何助力企业数字化转型?

    说起3D,估计许多读者朋友会在第一时间想起《阿凡达》系列和《侏罗纪公园》系列电影大作。每一帧细节纤毫毕现的逼真画面,让观众几乎分不清虚拟与现实,完全沉浸在导演打造的视觉盛宴中。 事实上,除了大家所熟知的3D影视动画之外,在建筑业,在制造业,在医疗业

    2024年02月12日
    浏览(47)
  • 了解VR虚拟现实的沉浸式效果及其技术特点!

    VR虚拟现实体验装置作为近年来人气火爆的科技产品,以其独特的沉浸式体验效果吸引了众多用户,那么,你知道这种 VR体验装置 是如何实现沉浸式体验效果的吗?它又具备了哪些技术特点呢? 一、 真实 的场景体验 VR 虚拟现实技术通过 三维建模技术和实时交互技术 , 精确

    2024年02月02日
    浏览(33)
  • Go Ethereum源码学习笔记000

    这个专栏的内容是免费的,因为自己这边都是基于开源库和开源内容整理的学习笔记,在这个过程中进行增删改查,将自己的理解融入其中,所以这里用开源的精神分享给大家:Free software, free knowledge。当然,开源精神和软件付费/知识付费并不冲突,而是求同存异。大家觉

    2024年02月14日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包