最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang使用ttl機(jī)制保存內(nèi)存數(shù)據(jù)方法詳解

 更新時(shí)間:2023年03月08日 09:56:28   作者:夢想畫家  
ttl(time-to-live) 數(shù)據(jù)存活時(shí)間,我們這里指數(shù)據(jù)在內(nèi)存中保存一段時(shí)間,超過期限則不能被讀取到,與Redis的ttl機(jī)制類似。本文僅實(shí)現(xiàn)ttl部分,不考慮序列化和反序列化

ttl(time-to-live) 數(shù)據(jù)存活時(shí)間,我們這里指數(shù)據(jù)在內(nèi)存中保存一段時(shí)間,超過期限則不能被讀取到,與Redis的ttl機(jī)制類似。本文僅實(shí)現(xiàn)ttl部分,不考慮序列化和反序列化。

獲取當(dāng)前時(shí)間

涉及時(shí)間計(jì)算,這里首先介紹如何獲取當(dāng)前時(shí)間,以及時(shí)間的精度,這里為了簡化,精度到秒級。

使用time.Now可以獲取當(dāng)前時(shí)間,time.Unix 或 time.UnixNano可以獲得時(shí)間戳。

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

輸出結(jié)果:

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

數(shù)據(jù)結(jié)構(gòu)

首先定義數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)及存儲(chǔ)數(shù)據(jù)容器的結(jié)構(gòu):

type Data struct {
	Key       string
	Value     interface{}
	Timestamp int64
}
type Heap struct {
	dataMx *sync.RWMutex
	data   map[string]Data
}

Data 包括key和value以及ttl時(shí)間(單位秒),Heap容器包括map類型data以及RWMutex讀寫鎖,讀寫鎖是支持并發(fā)操作。

下面定義Heap結(jié)構(gòu)一些方法。

Heap操作

主要方法包括New,Set,Del,Get三個(gè)方法。

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

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

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

測試ttl容器Heap

首先定義heap,然后調(diào)用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秒后調(diào)用Get方法,兩次直接結(jié)果和預(yù)期一致:

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

總結(jié)

本文解釋Golang如果實(shí)現(xiàn)ttl機(jī)制在內(nèi)存存儲(chǔ)自動(dòng)失效數(shù)據(jù)。首先介紹時(shí)間戳原理,然后定義數(shù)據(jù)結(jié)構(gòu),并簡單實(shí)現(xiàn)Set、Get、Del方法實(shí)現(xiàn)了ttl機(jī)制。未來再增加序列化功能:保存和恢復(fù)。參考實(shí)現(xiàn):https://github.com/leprosus/golang-ttl-map

到此這篇關(guān)于Golang使用ttl機(jī)制保存內(nèi)存數(shù)據(jù)方法詳解的文章就介紹到這了,更多相關(guān)Go保存內(nèi)存數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang中的自定義函數(shù)詳解

    Golang中的自定義函數(shù)詳解

    函數(shù)構(gòu)成代碼執(zhí)行的邏輯結(jié)構(gòu)。在Go語言中,函數(shù)的基本組成為:關(guān)鍵字func、函數(shù)名、參數(shù)列表、返回值、函數(shù)體和返回語句。
    2018-10-10
  • SingleFlight模式的Go并發(fā)編程學(xué)習(xí)

    SingleFlight模式的Go并發(fā)編程學(xué)習(xí)

    這篇文章主要為大家介紹了SingleFlight模式的Go并發(fā)編程學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • go slice 擴(kuò)容實(shí)現(xiàn)原理源碼解析

    go slice 擴(kuò)容實(shí)現(xiàn)原理源碼解析

    這篇文章主要為大家介紹了go slice 擴(kuò)容實(shí)現(xiàn)原理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • golang中包無法引入問題解決

    golang中包無法引入問題解決

    本文主要介紹了golang中包無法引入問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 深入了解Go的interface{}底層原理實(shí)現(xiàn)

    深入了解Go的interface{}底層原理實(shí)現(xiàn)

    本文主要介紹了Go的interface{}底層原理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Go語言使用Timeout Context取消任務(wù)的實(shí)現(xiàn)

    Go語言使用Timeout Context取消任務(wù)的實(shí)現(xiàn)

    本文主要介紹了Go語言使用Timeout Context取消任務(wù)的實(shí)現(xiàn),包括基本的任務(wù)取消和控制HTTP客戶端請求的超時(shí),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Go語言實(shí)現(xiàn)猜數(shù)字小游戲

    Go語言實(shí)現(xiàn)猜數(shù)字小游戲

    這篇文章主要為大家詳細(xì)介紹了Go語言實(shí)現(xiàn)猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • Go語言中切片(slice)和數(shù)組(array)的區(qū)別詳解

    Go語言中切片(slice)和數(shù)組(array)的區(qū)別詳解

    Go語言中切片(slice)和數(shù)組(array)是兩種不同的數(shù)據(jù)結(jié)構(gòu),它們在用法和行為上有一些重要區(qū)別,所以本文就通過一些代碼示例給大家詳細(xì)的介紹一下Go語言中切片(slice)和數(shù)組(array)的區(qū)別,需要的朋友可以參考下
    2023-09-09
  • go:gin輸出日志文件方式

    go:gin輸出日志文件方式

    這篇文章主要介紹了go:gin輸出日志文件方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • golang版本升級的簡單實(shí)現(xiàn)步驟

    golang版本升級的簡單實(shí)現(xiàn)步驟

    個(gè)人感覺Go在眾多高級語言中,是在各方面都比較高效的,下面這篇文章主要給大家介紹了關(guān)于golang版本升級的簡單實(shí)現(xiàn)步驟,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02

最新評論

南靖县| 宜兴市| 永靖县| 惠安县| 石嘴山市| 资源县| 宝清县| 洛川县| 宁波市| 洞口县| 中江县| 清新县| 淄博市| 洛阳市| 萝北县| 南充市| 邵东县| 通州市| 图木舒克市| 蒲城县| 衡东县| 沁水县| 大理市| 铜陵市| 元朗区| 贵港市| 札达县| 临颍县| 永年县| 桃江县| 苏尼特左旗| 桦甸市| 西和县| 平湖市| 肃南| 衡阳县| 安福县| 嘉峪关市| 芜湖县| 金平| 泊头市|