成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go中使用sync.Map實(shí)現(xiàn)線程安全的緩存

開(kāi)發(fā) 后端
在本文中,我們展示了如何使用sync.Map包在Go中實(shí)現(xiàn)一個(gè)簡(jiǎn)單、線程安全的緩存。

緩存是優(yōu)化現(xiàn)代應(yīng)用程序性能的關(guān)鍵方面。它允許您存儲(chǔ)并快速檢索昂貴操作的結(jié)果或經(jīng)常訪問(wèn)的數(shù)據(jù),減少了反復(fù)重新計(jì)算或獲取數(shù)據(jù)的需要。在本文中,我們將探討如何使用sync.Map包在Go中實(shí)現(xiàn)線程安全的緩存。這種緩存實(shí)現(xiàn)支持緩存條目的過(guò)期,確保過(guò)時(shí)的數(shù)據(jù)不會(huì)滯留在緩存中。

為什么要費(fèi)心

在我們開(kāi)始實(shí)現(xiàn)自己的線程安全內(nèi)存緩存之前,讓我們考慮一下其優(yōu)缺點(diǎn)。考慮到替代方案是使用為緩存而發(fā)明的、有長(zhǎng)期使用和支持歷史的外部庫(kù)(工具),讓我們思考一下優(yōu)點(diǎn)和缺點(diǎn)。

使用Go的sync.Map實(shí)現(xiàn)自己的線程安全緩存相比使用像Redis這樣的外部庫(kù)有幾個(gè)優(yōu)點(diǎn),這取決于您的用例和要求。以下是使用sync.Map創(chuàng)建自己的緩存可能有優(yōu)勢(shì)的一些原因:

  • 更低的延遲:使用像sync.Map這樣的內(nèi)存緩存時(shí),數(shù)據(jù)存儲(chǔ)在應(yīng)用程序的內(nèi)存中。這可能導(dǎo)致比需要應(yīng)用程序和緩存服務(wù)之間的網(wǎng)絡(luò)通信的單獨(dú)服務(wù),如Redis,有更低的訪問(wèn)延遲。
  • 更簡(jiǎn)單的部署:使用基于sync.Map的緩存,無(wú)需部署、配置和維護(hù)像Redis這樣的額外服務(wù)。您的緩存解決方案是應(yīng)用程序的一部分,使部署過(guò)程更簡(jiǎn)單,并可能減少操作復(fù)雜性。
  • 減少資源使用:與像Redis這樣的外部服務(wù)相比,使用sync.Map的內(nèi)存緩存通常消耗更少的資源,從而節(jié)省了內(nèi)存和CPU使用。這對(duì)于小規(guī)模的應(yīng)用程序或資源緊張的應(yīng)用程序可能更加經(jīng)濟(jì)高效。
  • 更容易集成:在Go應(yīng)用程序中直接使用sync.Map實(shí)現(xiàn)緩存可以更容易地與現(xiàn)有的代碼庫(kù)集成。您不需要學(xué)習(xí)新的API或管理到外部服務(wù)的連接。
  • 定制性:創(chuàng)建自己的緩存實(shí)現(xiàn)時(shí),您可以完全控制其行為和功能。您可以輕松地根據(jù)具體需求調(diào)整緩存,針對(duì)您的用例進(jìn)行優(yōu)化,并根據(jù)需要添加自定義過(guò)期策略或其他功能。
  • 樂(lè)趣:創(chuàng)建實(shí)現(xiàn)緩存的自己的代碼段會(huì)帶來(lái)很多樂(lè)趣,并幫助更好地理解提供緩存功能的外部庫(kù)。更好地理解它們有助于更好地利用它們提供的所有功能。

但是,值得注意的是,使用像Redis這樣的外部緩存解決方案對(duì)于較大規(guī)模的應(yīng)用程序或那些有更復(fù)雜的緩存需求的應(yīng)用程序有其自身的一系列優(yōu)勢(shì)。使用Redis的一些好處包括:

  • 可擴(kuò)展性:Redis設(shè)計(jì)用于高性能,并可以水平擴(kuò)展以處理大量請(qǐng)求和數(shù)據(jù)大小。
  • 持久性:Redis支持不同級(jí)別的數(shù)據(jù)持久性,確保您的緩存數(shù)據(jù)在重啟或崩潰后仍然存在。
  • 高級(jí)功能:除了簡(jiǎn)單的鍵值緩存外,Redis還提供了一系列功能,如數(shù)據(jù)結(jié)構(gòu)、發(fā)布/訂閱消息等。

最終,選擇使用sync.Map實(shí)現(xiàn)自己的緩存還是使用像Redis這樣的外部庫(kù)將取決于您的具體需求、應(yīng)用程序的規(guī)模以及您在性能、復(fù)雜性和資源方面愿意做的權(quán)衡。

此外,實(shí)現(xiàn)您的緩存會(huì)帶來(lái)樂(lè)趣并幫助更好地理解像Redis這樣的更復(fù)雜的產(chǎn)品。因此,我們將在此文章中實(shí)現(xiàn)一個(gè)。

為什么我們使用sync.Map

簡(jiǎn)單地說(shuō),因?yàn)樗昝赖貪M足了我們的需要。更深入的解釋 - sync.Map是Go標(biāo)準(zhǔn)庫(kù)中的一個(gè)并發(fā)的、線程安全的map實(shí)現(xiàn)。它設(shè)計(jì)用于在多個(gè)goroutine并發(fā)訪問(wèn)映射的情況下使用,并且鍵的數(shù)量是未知的或隨時(shí)間變化的。

值得注意的是,雖然sync.Map是特定用例的一個(gè)很好的選擇,但它并不意味著要替換所有場(chǎng)景的內(nèi)置map類型。特別是,sync.Map最適合以下情況:

  • 映射主要是讀取密集型,偶爾寫(xiě)入。
  • 鍵的數(shù)量隨時(shí)間變化或事先不知道。
  • 映射由多個(gè)goroutine并發(fā)訪問(wèn)。

在鍵的數(shù)量是固定的或事先知道的情況下,且映射可以預(yù)先分配,使用適當(dāng)?shù)耐饺鐂ync.Mutex或sync.RWMutex的內(nèi)置map類型可能會(huì)提供更好的性能。

創(chuàng)建SafeCache

如上所述,我們的SafeCache是一個(gè)簡(jiǎn)單的、線程安全的緩存,使用Go的sync.Map存儲(chǔ)其鍵值對(duì)。

首先,我們定義一個(gè)CacheEntry結(jié)構(gòu)來(lái)保存值及其過(guò)期時(shí)間戳:

type CacheEntry struct {
    value      interface{}
    expiration int64
}

在SafeCache結(jié)構(gòu)中嵌入了一個(gè)sync.Map,它提供了對(duì)鍵值對(duì)的并發(fā)安全訪問(wèn):

type SafeCache struct {
    syncMap sync.Map
}

向緩存中添加值

然后我們定義了一個(gè) Set 方法,該方法允許我們?cè)诰彺嬷写鎯?chǔ)一個(gè)帶有指定生存時(shí)間(TTL,Time To Live)的值。TTL 決定了緩存條目應(yīng)被認(rèn)為有效的時(shí)間長(zhǎng)度。一旦 TTL 過(guò)期,在下一個(gè)清理周期中將會(huì)移除該緩存條目。

func (sc *SafeCache) Set(key string, value interface{}, ttl time.Duration) {
    expiration := time.Now().Add(ttl).UnixNano()
    sc.syncMap.Store(key, CacheEntry{value: value, expiration: expiration})
}

從緩存中檢索值

接下來(lái)需要的方法是 Get,它使用鍵從緩存中檢索值。如果沒(méi)有找到該值或該值已過(guò)期,該方法將返回 false:

func (sc *SafeCache) Get(key string) (interface{}, bool) {
    // ... (see the provided code for the full implementation)
}

在 Get 方法中重要的是從緩存加載值后進(jìn)行類型斷言。我們依賴于 sync.Map 的 Load 方法,該方法返回接口。

entry, found := sc.syncMap.Load(key)
 if !found {
  return nil, false
 }
 // Type assertion to CacheEntry, as entry is an interface{}
 cacheEntry := entry.(CacheEntry)

從緩存中移除值

當(dāng)然,我們還需要一個(gè) Delete 方法,使我們能夠從緩存中移除一個(gè)值:

func (sc *SafeCache) Delete(key string) {
    sc.syncMap.Delete(key)
}

清理過(guò)期條目

我們通過(guò) CleanUp 方法擴(kuò)展了緩存,該方法負(fù)責(zé)定期從緩存中刪除過(guò)期的條目。它使用 sync.Map 提供的 Range 方法遍歷緩存中的所有鍵值對(duì),并刪除那些TTL已過(guò)期的條目:

func (sc *SafeCache) CleanUp() {
    // ... (see the provided code for the full implementation)
}

要運(yùn)行 CleanUp 方法,我們可以在初始化緩存時(shí)啟動(dòng)一個(gè)單獨(dú)的 Goroutine:

cache := &SafeCache{}
go cache.CleanUp()

完整的代碼片段

package cache

import (
 "sync"
 "time"
)

// CacheEntry is a value stored in the cache.
type CacheEntry struct {
 value      interface{}
 expiration int64
}

// SafeCache is a thread-safe cache.
type SafeCache struct {
 syncMap sync.Map
}

// Set stores a value in the cache with a given TTL
// (time to live) in seconds.
func (sc *SafeCache) Set(key string, value interface{}, ttl time.Duration) {
 expiration := time.Now().Add(ttl).UnixNano()
 sc.syncMap.Store(key, CacheEntry{value: value, expiration: expiration})
}

// Get retrieves a value from the cache. If the value is not found
// or has expired, it returns false.
func (sc *SafeCache) Get(key string) (interface{}, bool) {
 entry, found := sc.syncMap.Load(key)
 if !found {
  return nil, false
 }
 // Type assertion to CacheEntry, as entry is an interface{}
 cacheEntry := entry.(CacheEntry)
 if time.Now().UnixNano() > cacheEntry.expiration {
  sc.syncMap.Delete(key)
  return nil, false
 }
 return cacheEntry.value, true
}

// Delete removes a value from the cache.
func (sc *SafeCache) Delete(key string) {
 sc.syncMap.Delete(key)
}

// CleanUp periodically removes expired entries from the cache.
func (sc *SafeCache) CleanUp() {
 for {
  time.Sleep(1 * time.Minute)
  sc.syncMap.Range(func(key, entry interface{}) bool {
   cacheEntry := entry.(CacheEntry)
   if time.Now().UnixNano() > cacheEntry.expiration {
    sc.syncMap.Delete(key)
   }
   return true
  })
 }
}

最后,你可以運(yùn)行以下的 main.go 程序來(lái)檢查緩存是否工作。我們創(chuàng)建了一個(gè)HTTP服務(wù)器,它在“/compute”端點(diǎn)監(jiān)聽(tīng)請(qǐng)求。該服務(wù)器接受一個(gè)整數(shù)n作為查詢參數(shù),并返回昂貴計(jì)算的結(jié)果(在這種情況下,帶有模擬延遲的簡(jiǎn)單平方操作)。服務(wù)器首先檢查緩存,看看給定輸入的結(jié)果是否已經(jīng)被緩存;如果沒(méi)有,它會(huì)計(jì)算結(jié)果,將其存儲(chǔ)在緩存中,并將其返回給客戶端。

要測(cè)試服務(wù)器,運(yùn)行代碼并請(qǐng)求http://localhost:8080/compute?n=5。第一個(gè)請(qǐng)求會(huì)花費(fèi)更長(zhǎng)的時(shí)間(由于模擬的延遲),但具有相同n的后續(xù)請(qǐng)求將立即返回緩存的結(jié)果。

package main

import (
 "fmt"
 "log"
 "net/http"
 "safe-cache/cache"
 "strconv"
 "time"
)


func expensiveComputation(n int) int {
 // Simulate an expensive computation
 time.Sleep(2 * time.Second)
 return n * n
}

func main() {
 safeCache := &cache.SafeCache{}
 // Start a goroutine to periodically clean up the cache
 go safeCache.CleanUp()

 http.HandleFunc("/compute", func(w http.ResponseWriter, r *http.Request) {
  query := r.URL.Query()
  n, err := strconv.Atoi(query.Get("n"))
  if err != nil {
   http.Error(w, "Invalid input", http.StatusBadRequest)
   return
  }

  cacheKey := fmt.Sprintf("result_%d", n)
  cachedResult, found := safeCache.Get(cacheKey)
  var result int
  if found {
   result = cachedResult.(int)
  } else {
   result = expensiveComputation(n)
   safeCache.Set(cacheKey, result, 1*time.Minute)
  }

  _, err = fmt.Fprintf(w, "Result: %d\n", result)
  if err != nil {
   return
  }
 })

 log.Fatal(http.ListenAndServe(":8080", nil))
}

結(jié)論

在本文中,我們展示了如何使用sync.Map包在Go中實(shí)現(xiàn)一個(gè)簡(jiǎn)單、線程安全的緩存。

這個(gè)緩存實(shí)現(xiàn)支持基于TTL的過(guò)期的鍵值存儲(chǔ),并可以輕松地集成到你的Go應(yīng)用中,以提高性能并減少對(duì)你的數(shù)據(jù)源或計(jì)算資源的負(fù)載。

責(zé)任編輯:趙寧寧 來(lái)源: 技術(shù)的游戲
相關(guān)推薦

2024-12-03 08:53:46

Go語(yǔ)言類型

2021-05-18 09:03:16

Gomapslice

2025-02-12 08:50:22

2025-03-06 08:54:24

泛型類型MapGo1

2023-10-28 16:22:21

Go接口

2023-05-15 08:01:16

Go語(yǔ)言

2023-11-27 19:39:46

Goprotobuf

2024-05-27 09:35:04

C++線程安全Map

2023-12-25 09:58:25

sync包Go編程

2012-06-05 09:54:50

Windows Pho

2019-10-29 19:49:48

Java線程安全

2023-03-21 09:07:38

HashMap線程安全

2021-05-14 08:58:18

非線性安全Go

2024-04-07 00:04:00

Go語(yǔ)言Map

2024-10-14 08:51:52

協(xié)程Go語(yǔ)言

2024-06-04 08:32:40

2024-11-14 11:29:38

2023-07-28 08:04:56

StringHeaatomic線程

2013-06-25 09:52:32

GoGo語(yǔ)言Go編程

2021-11-29 22:59:34

Go Dockertest集成
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日本高清中文字幕 | www.国产| 亚洲精品久久久久久久久久久 | 久久久久久久久99 | 日本一区二区三区精品视频 | 国产精品伦理一区二区三区 | h视频网站在线观看 | 欧美日批 | 在线观看视频一区二区三区 | 国产精品美女久久久久aⅴ国产馆 | 日韩精品一区在线 | 国产精彩视频 | 国产精品一区二区精品 | 91欧美 | 天天视频成人 | 国产精品美女久久久 | 九九视频在线观看 | 国产高清视频一区 | 亚洲精品一区二区三区在线观看 | 久久久久久久久久爱 | 欧美在线高清 | 亚洲另类视频 | 狠狠亚洲| 亚洲综合中文字幕在线观看 | 欧美亚州 | 91在线区| 精品一区二区三区电影 | 国产91综合一区在线观看 | 九九热国产精品视频 | 综合色久| 成人免费一区二区三区视频网站 | 精品国产一区二区在线 | 日本中文字幕视频 | www.欧美视频 | www.99re5.com| 青青草原综合久久大伊人精品 | 午夜精品久久久久久久久久久久久 | 91看片网| 国产午夜精品一区二区三区嫩草 | 成人性视频免费网站 | 狠狠的干狠狠的操 |