Golang如何使用ttl机制保存内存数据
本篇内容介绍了“Golang如何使用ttl机制保存内存数据”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
ttl(time-to-live) 数据存活时间,我们这里指数据在内存中保存一段时间,超过期限则不能被读取到,与Redis的ttl机制类似。
获取当前时间
涉及时间计算,这里首先介绍如何获取当前时间,以及时间的精度,这里为了简化,精度到秒级。
使用time.Now可以获取当前时间,time.Unix 或 time.UnixNano可以获得时间戳。
now := time.Now() // current local time
sec := now.Unix() // number of seconds since January 1, 1970 UTC
nsec := now.UnixNano() // number of nanoseconds since January 1, 1970 UTC
fmt.Println(now) // time.Time
fmt.Println(sec) // int64
fmt.Println(nsec) // int64
输出结果:
2023-02-19 16:52:51.5894329 +0800 CST m=+0.004286801
1676796771
1676796771589432900
数据结构
首先定义数据结构,数据结构及存储数据容器的结构:
type Data struct {
Key string
Value interface{}
Timestamp int64
}
type Heap struct {
dataMx *sync.RWMutex
data map[string]Data
}
Data 包括key和value以及ttl时间(单位秒),Heap容器包括map类型data以及RWMutex读写锁,读写锁是支持并发操作。
下面定义Heap结构一些方法。
Heap操作
主要方法包括New,Set,Del,Get三个方法。
func New() *Heap {
return &Heap{
dataMx: &sync.RWMutex{},
data: map[string]Data{},
}
}
func (h *Heap) Set(key string, value interface{}, ttl int64) {
if ttl == 0 {
return
}
data := Data{
Key: key,
Value: value,
Timestamp: time.Now().Unix(),
}
if ttl > 0 {
data.Timestamp += ttl
} else if ttl < 0 {
data.Timestamp = -1
}
h.dataMx.Lock()
h.data[key] = data
h.dataMx.Unlock()
}
func (h *Heap) Get(key string) (val interface{}, ok bool) {
var data Data
h.dataMx.RLock()
data, ok = h.data[key]
h.dataMx.RUnlock()
if ok {
if data.Timestamp != -1 && data.Timestamp <= time.Now().Unix() {
h.Del(key)
ok = false
} else {
val = data.Value
}
}
return
}
func (h *Heap) Del(key string) {
h.dataMx.RLock()
_, ok := h.data[key]
h.dataMx.RUnlock()
if !ok {
return
}
h.dataMx.Lock()
delete(h.data, key)
h.dataMx.Unlock()
}
New方法无需多解释,我们直接看Set方法。
Set方法实现逻辑:如果ttl为0则直接返回,反之先初始化Data数据,这里初始化当前时间为Data的时间戳;接着判断ttl,如果大于零则Data的时间戳加上ttl,反之为-1;下面开始通过读写锁存储Heap的data。
Del方法,首先通过读锁读取key对应数据,如果失败直接返回(可能已经过期,其他协程已经获取过),反之直接删除数据。
Get方法,读取逻辑与Del一样,如果正确读取,则判断时间戳,不等于-1且小于当前时间则表明已过期,调用Del方法进行删除,返回nil和false;反之返回value及true。
测试ttl容器Heap
首先定义heap,然后调用Set方法,增加数据key,value,ttl为2秒:
func main() {
keyTag := "key"
heap := New()
defer func() {
heap.Del(keyTag)
}()
heap.Set(keyTag, "value", 2)
time.Sleep(1 * time.Second)
val, flag := heap.Get(keyTag)
fmt.Printf("%v, %v
", val, flag)
time.Sleep(1 * time.Second)
val, flag = heap.Get(keyTag)
fmt.Printf("%v, %v
", val, flag)
}
然后模拟等待1秒后调用Get方法,两次直接结果和预期一致:
value, true
<nil>, false
完整代码
下面给出完整代码:
package main
import (
"fmt"
"sync"
"time"
)
type Data struct {
Key string
Value interface{}
Timestamp int64
}
type Heap struct {
dataMx *sync.RWMutex
data map[string]Data
}
func New() *Heap {
return &Heap{
dataMx: &sync.RWMutex{},
data: map[string]Data{},
}
}
func (h *Heap) Set(key string, value interface{}, ttl int64) {
if ttl == 0 {
return
}
data := Data{
Key: key,
Value: value,
Timestamp: time.Now().Unix(),
}
if ttl > 0 {
data.Timestamp += ttl
} else if ttl < 0 {
data.Timestamp = -1
}
h.dataMx.Lock()
h.data[key] = data
h.dataMx.Unlock()
}
func (h *Heap) Get(key string) (val interface{}, ok bool) {
var data Data
h.dataMx.RLock()
data, ok = h.data[key]
h.dataMx.RUnlock()
if ok {
if data.Timestamp != -1 && data.Timestamp <= time.Now().Unix() {
h.Del(key)
ok = false
} else {
val = data.Value
}
}
return
}
func (h *Heap) Del(key string) {
h.dataMx.RLock()
_, ok := h.data[key]
h.dataMx.RUnlock()
if !ok {
return
}
h.dataMx.Lock()
delete(h.data, key)
h.dataMx.Unlock()
}
func main() {
keyTag := "key"
heap := New()
defer func() {
heap.Del(keyTag)
}()
heap.Set(keyTag, "value", 2)
time.Sleep(1 * time.Second)
val, flag := heap.Get(keyTag)
fmt.Printf("%v, %v
", val, flag)
time.Sleep(1 * time.Second)
val, flag = heap.Get(keyTag)
fmt.Printf("%v, %v
", val, flag)
}
相关内容
这些是最新的
热门排行
- THINKPHP5+GatewayWorker+Workerman 开发在线客服系统
- 在手机浏览器网页中点击链接跳转到微信界面的方法
- 尊云网站目录系统 ThinkPHP5网站分类目录程序 v2.2.221011
- CentOS 7安装shadowsock(一键安装脚本)
- AdminTemplate 基于LayUI 2.4.5实现的网站后台管理模板
- 用NW.js(node-webkit)开发多平台的桌面客户端
- PHP生成随机昵称/用户名
- THINKPHP5网站分类目录程序 尊云网站目录系统
- 织梦(DEDECMS)微信支付接口 微信插件
- 基于LayUI开发的 网站后台管理模板 BeginnerAdmin
- 响应式后台网站模板 - AMA.ADMIN
- layuiAdmin后台管理模板 Iframe版
- LayUI 1.0.9 升级 至 LayUI 2.1.4 方法
- 简洁清爽的会员中心模板
- jQuery幸运大转盘抽奖活动代码