溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang如何使用ttl機制保存內存數(shù)據(jù)

發(fā)布時間:2023-03-08 10:26:45 來源:億速云 閱讀:111 作者:iii 欄目:開發(fā)技術

本篇內容介紹了“Golang如何使用ttl機制保存內存數(shù)據(jù)”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

ttl(time-to-live) 數(shù)據(jù)存活時間,我們這里指數(shù)據(jù)在內存中保存一段時間,超過期限則不能被讀取到,與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

數(shù)據(jù)結構

首先定義數(shù)據(jù)結構,數(shù)據(jù)結構及存儲數(shù)據(jù)容器的結構:

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讀寫鎖,讀寫鎖是支持并發(fā)操作。

下面定義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方法實現(xiàn)邏輯:如果ttl為0則直接返回,反之先初始化Data數(shù)據(jù),這里初始化當前時間為Data的時間戳;接著判斷ttl,如果大于零則Data的時間戳加上ttl,反之為-1;下面開始通過讀寫鎖存儲Heap的data。

Del方法,首先通過讀鎖讀取key對應數(shù)據(jù),如果失敗直接返回(可能已經過期,其他協(xié)程已經獲取過),反之直接刪除數(shù)據(jù)。

Get方法,讀取邏輯與Del一樣,如果正確讀取,則判斷時間戳,不等于-1且小于當前時間則表明已過期,調用Del方法進行刪除,返回nil和false;反之返回value及true。

測試ttl容器Heap

首先定義heap,然后調用Set方法,增加數(shù)據(jù)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\n", val, flag)
	time.Sleep(1 * time.Second)
	val, flag = heap.Get(keyTag)
	fmt.Printf("%v, %v\n", 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\n", val, flag)
	time.Sleep(1 * time.Second)
	val, flag = heap.Get(keyTag)
	fmt.Printf("%v, %v\n", val, flag)
}

“Golang如何使用ttl機制保存內存數(shù)據(jù)”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI