介绍
在这个项目中,你将学习如何基于 Go 语言的 singleflight 包实现一个支持过期时间的缓存库。这个缓存库可用于分布式系统中缓存请求的执行结果,从而提升你的应用程序性能。
👀 预览
$ /usr/local/go/bin/go test --race
PASS
ok cacheflight 1.263s
🎯 任务
在这个项目中,你将学习:
- 如何初始化一个 Go 模块并安装所需的包
- 如何使用
singleflight包实现缓存库 - 如何测试缓存库以确保其按预期工作
🏆 成果
完成这个项目后,你将能够:
- 理解缓存的基本概念以及 Go 语言中的
singleflight包 - 实现一个支持过期时间的缓存库
- 将缓存库集成到你的分布式系统中以提升应用程序性能
初始化模块并安装所需包
在这一步中,你将学习如何初始化模块并为项目安装所需的包。
在
/home/labex/project目录中打开终端。使用以下命令初始化模块:
/usr/local/go/bin/go mod init cacheflight使用以下命令安装所需的包:
/usr/local/go/bin/go get github.com/golang/groupcache/singleflight /usr/local/go/bin/go get github.com/stretchr/testify/assert
实现缓存库
在这一步中,你将基于 singleflight 包实现缓存库。
在
/home/labex/project目录中打开cacheflight.go文件。在
import中添加必要的内容。import ( "sync" "time" "github.com/golang/groupcache/singleflight" )在
type Group和type cacheResult中添加必要的内容。// cacheResult 是缓存结果 type cacheResult struct { data interface{} // 缓存数据 ctime time.Time // 缓存创建时间 isRunning chan bool // 函数是否正在运行 } // Group 是核心结构体 type Group struct { cacheExpiration time.Duration // 缓存过期时间 sfg *singleflight.Group // singleflight 组 cache map[string]cacheResult // 缓存结果 mu sync.Mutex // 互斥锁 }实现
NewGroup函数,以返回一个具有指定缓存过期时间的新缓存组。func NewGroup(cacheExpiration time.Duration) (group *Group) { group = &Group{ sfg: &singleflight.Group{}, cache: make(map[string]cacheResult), cacheExpiration: cacheExpiration, } return }实现
do函数来处理缓存逻辑。func (g *Group) do(key string, fn func() (interface{}, error)) (ret interface{}, err error) { return g.sfg.Do(key, func() (interface{}, error) { g.mu.Lock() result, ok := g.cache[key] if result.isRunning!= nil { g.mu.Unlock() // 等待 fn 完成 <-result.isRunning return g.do(key, fn) } else if!ok || result.ctime.Add(g.cacheExpiration).Before(time.Now()) { // 如果缓存不存在或已过期 var run = make(chan bool) result.isRunning = run g.cache[key] = result // 当 fn 完成并关闭 run 通道时,让其他 goroutine 可以获取缓存 defer close(run) } else { // 如果缓存存在且未过期 g.mu.Unlock() return result.data, nil } g.mu.Unlock() // 不同的键可以同时运行 ret, err = fn() if err!= nil { return ret, nil } result = cacheResult{ data: ret, ctime: time.Now(), } g.mu.Lock() g.cache[key] = result g.mu.Unlock() return ret, nil }) }实现
Do函数作为do函数的包装器。func (g *Group) Do(key string, fn func() (interface{}, error)) (ret interface{}, err error) { return g.do(key, fn) }
测试缓存库
在这一步中,你将测试缓存库以确保其按预期工作。
在
/home/labex/project目录中打开终端。运行以下命令来执行测试:
cd /home/labex/project /usr/local/go/bin/go test --race如果缓存函数实现正确,你将看到以下输出:
PASS ok cacheflight 1.263s如果你遇到超时错误,请在终端中执行以下命令,然后点击重新检查按钮以通过检查:
cd /home/labex/project /usr/local/go/bin/go test --race
恭喜!你已成功基于 singleflight 包实现了缓存库。现在,你可以在分布式系统中使用此库来缓存请求的执行结果并提升应用程序的性能。
总结
恭喜!你已完成这个项目。你可以在 LabEx 中练习更多实验来提升你的技能。



