-
在 /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)
}