使用示例
执行后,输出结果为:
v1
1
true
v1
过期控制
package main
import (
"fmt"
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
"time"
)
func main() {
var (
ctx = gctx.New()
)
// 当键名不存在时写入,设置过期时间1000毫秒
_, err := gcache.SetIfNotExist(ctx, "k1", "v1", time.Second)
if err != nil {
panic(err)
}
// 打印当前的键名列表
keys, err := gcache.Keys(ctx)
if err != nil {
panic(err)
}
// 打印当前的键值列表
values, err := gcache.Values(ctx)
if err != nil {
panic(err)
}
fmt.Println(values)
value, err := gcache.GetOrSet(ctx, "k2", "v2", 0)
if err != nil {
panic(err)
}
fmt.Println(value)
// 打印当前的键值对
data1, err := gcache.Data(ctx)
if err != nil {
panic(err)
}
fmt.Println(data1)
// 等待1秒,以便k1:v1自动过期
time.Sleep(time.Second)
// 再次打印当前的键值对,发现k1:v1已经过期,只剩下k2:v2
data2, err := gcache.Data(ctx)
if err != nil {
panic(err)
}
fmt.Println(data2)
}
执行后,输出结果为:
需要注意的是,GetOrSetFunc
的缓存方法参数f
是在缓存的锁机制外执行,因此在f
内部也可以嵌套调用GetOrSetFunc
。但如果f
的执行比较耗时,高并发的时候容易出现f
被多次执行的情况(缓存设置只有第一个执行的f
返回结果能够设置成功,其余的被抛弃掉)。而GetOrSetFuncLock
的缓存方法f
是在缓存的锁机制内执行,因此可以保证当缓存项不存在时只会执行一次f
,但是缓存写锁的时间随着f
方法的执行时间而定。
我们来看一个示例:
package main
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
"time"
)
func main() {
var (
ch = make(chan struct{}, 0)
ctx = gctx.New()
key = `key`
value = `value`
)
for i := 0; i < 10; i++ {
go func(index int) {
<-ch
_, err := gcache.GetOrSetFuncLock(ctx, key, func() (interface{}, error) {
fmt.Println(index, "entered")
return value, nil
}, 0)
if err != nil {
panic(err)
}
}(i)
}
close(ch)
time.Sleep(time.Second)
}
9 entered
可以看到,多个goroutine
同时调用GetOrSetFuncLock
方法时,由于该方法有并发安全控制,因此最终只有一个goroutine
的数值生成函数执行成功,成功之后其他goroutine
拿到数据后则立即返回不再执行对应的数值生成函数。
LRU
缓存淘汰控制
执行后,输出结果为:
10
[2 3 5 6 7 0 1 4 8 9]
1
2
[1 9]
性能测试
CPU: Intel(R) Core(TM) i5-4460 CPU @ 3.20GHz