Golang如何使用ttl机制保存内存数据

其他教程   发布日期:2023年08月04日   浏览次数:443

本篇内容介绍了“Golang如何使用ttl机制保存内存数据”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

ttl(time-to-live) 数据存活时间,我们这里指数据在内存中保存一段时间,超过期限则不能被读取到,与Redis的ttl机制类似。

获取当前时间

涉及时间计算,这里首先介绍如何获取当前时间,以及时间的精度,这里为了简化,精度到秒级。

使用time.Now可以获取当前时间,time.Unix 或 time.UnixNano可以获得时间戳。

  1. now := time.Now() // current local time
  2. sec := now.Unix() // number of seconds since January 1, 1970 UTC
  3. nsec := now.UnixNano() // number of nanoseconds since January 1, 1970 UTC
  4. fmt.Println(now) // time.Time
  5. fmt.Println(sec) // int64
  6. fmt.Println(nsec) // int64

输出结果:

2023-02-19 16:52:51.5894329 +0800 CST m=+0.004286801
1676796771
1676796771589432900

数据结构

首先定义数据结构,数据结构及存储数据容器的结构:

  1. type Data struct {
  2. Key string
  3. Value interface{}
  4. Timestamp int64
  5. }
  6. type Heap struct {
  7. dataMx *sync.RWMutex
  8. data map[string]Data
  9. }

Data 包括key和value以及ttl时间(单位秒),Heap容器包括map类型data以及RWMutex读写锁,读写锁是支持并发操作。

下面定义Heap结构一些方法。

Heap操作

主要方法包括New,Set,Del,Get三个方法。

  1. func New() *Heap {
  2. return &Heap{
  3. dataMx: &sync.RWMutex{},
  4. data: map[string]Data{},
  5. }
  6. }
  7. func (h *Heap) Set(key string, value interface{}, ttl int64) {
  8. if ttl == 0 {
  9. return
  10. }
  11. data := Data{
  12. Key: key,
  13. Value: value,
  14. Timestamp: time.Now().Unix(),
  15. }
  16. if ttl > 0 {
  17. data.Timestamp += ttl
  18. } else if ttl < 0 {
  19. data.Timestamp = -1
  20. }
  21. h.dataMx.Lock()
  22. h.data[key] = data
  23. h.dataMx.Unlock()
  24. }
  25. func (h *Heap) Get(key string) (val interface{}, ok bool) {
  26. var data Data
  27. h.dataMx.RLock()
  28. data, ok = h.data[key]
  29. h.dataMx.RUnlock()
  30. if ok {
  31. if data.Timestamp != -1 && data.Timestamp <= time.Now().Unix() {
  32. h.Del(key)
  33. ok = false
  34. } else {
  35. val = data.Value
  36. }
  37. }
  38. return
  39. }
  40. func (h *Heap) Del(key string) {
  41. h.dataMx.RLock()
  42. _, ok := h.data[key]
  43. h.dataMx.RUnlock()
  44. if !ok {
  45. return
  46. }
  47. h.dataMx.Lock()
  48. delete(h.data, key)
  49. h.dataMx.Unlock()
  50. }

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秒:

  1. func main() {
  2. keyTag := "key"
  3. heap := New()
  4. defer func() {
  5. heap.Del(keyTag)
  6. }()
  7. heap.Set(keyTag, "value", 2)
  8. time.Sleep(1 * time.Second)
  9. val, flag := heap.Get(keyTag)
  10. fmt.Printf("%v, %v
  11. ", val, flag)
  12. time.Sleep(1 * time.Second)
  13. val, flag = heap.Get(keyTag)
  14. fmt.Printf("%v, %v
  15. ", val, flag)
  16. }

然后模拟等待1秒后调用Get方法,两次直接结果和预期一致:

value, true
<nil>, false

完整代码

下面给出完整代码:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. type Data struct {
  8. Key string
  9. Value interface{}
  10. Timestamp int64
  11. }
  12. type Heap struct {
  13. dataMx *sync.RWMutex
  14. data map[string]Data
  15. }
  16. func New() *Heap {
  17. return &Heap{
  18. dataMx: &sync.RWMutex{},
  19. data: map[string]Data{},
  20. }
  21. }
  22. func (h *Heap) Set(key string, value interface{}, ttl int64) {
  23. if ttl == 0 {
  24. return
  25. }
  26. data := Data{
  27. Key: key,
  28. Value: value,
  29. Timestamp: time.Now().Unix(),
  30. }
  31. if ttl > 0 {
  32. data.Timestamp += ttl
  33. } else if ttl < 0 {
  34. data.Timestamp = -1
  35. }
  36. h.dataMx.Lock()
  37. h.data[key] = data
  38. h.dataMx.Unlock()
  39. }
  40. func (h *Heap) Get(key string) (val interface{}, ok bool) {
  41. var data Data
  42. h.dataMx.RLock()
  43. data, ok = h.data[key]
  44. h.dataMx.RUnlock()
  45. if ok {
  46. if data.Timestamp != -1 && data.Timestamp <= time.Now().Unix() {
  47. h.Del(key)
  48. ok = false
  49. } else {
  50. val = data.Value
  51. }
  52. }
  53. return
  54. }
  55. func (h *Heap) Del(key string) {
  56. h.dataMx.RLock()
  57. _, ok := h.data[key]
  58. h.dataMx.RUnlock()
  59. if !ok {
  60. return
  61. }
  62. h.dataMx.Lock()
  63. delete(h.data, key)
  64. h.dataMx.Unlock()
  65. }
  66. func main() {
  67. keyTag := "key"
  68. heap := New()
  69. defer func() {
  70. heap.Del(keyTag)
  71. }()
  72. heap.Set(keyTag, "value", 2)
  73. time.Sleep(1 * time.Second)
  74. val, flag := heap.Get(keyTag)
  75. fmt.Printf("%v, %v
  76. ", val, flag)
  77. time.Sleep(1 * time.Second)
  78. val, flag = heap.Get(keyTag)
  79. fmt.Printf("%v, %v
  80. ", val, flag)
  81. }

以上就是Golang如何使用ttl机制保存内存数据的详细内容,更多关于Golang如何使用ttl机制保存内存数据的资料请关注九品源码其它相关文章!