b-Go-成功线程安保的缓存-sync.Map-中经常使用-b
缓存是提升现代运行程序性能的关键方面。它准许您存储并极速检索低廉操作的结果或经常访问的数据,缩小了重复从新计算或失掉数据的须要。在本文中,咱们将讨论如何经常使用sync.Map包在Go中成功线程安保的缓存。这种缓存成功支持缓存条目的过时,确保过时的数据不会滞留在缓存中。
为什么要费神
在咱们开局成功自己的线程安保内存缓存之前,让咱们思索一下其优缺陷。思索到代替打算是经常使用为缓存而发明的、有常年经常使用和支持历史的外部库(工具),让咱们思索一下优势和缺陷。
经常使用Go的sync.Map成功自己的线程安保缓存相比经常使用像这样的外部库有几个优势,这取决于您的用例和要求。以下是经常使用sync.Map创立自己的缓存或许有优势的一些要素:
然而,值得留意的是,经常使用像Redis这样的外部缓存处置打算关于较大规模的运行程序或那些有更复杂的缓存需求的运行程序有其自身的一系列优势。经常使用Redis的一些好处包含:
最终,选用经常使用sync.Map成功自己的缓存还是经常使用像Redis这样的外部库将取决于您的详细需求、运行程序的规模以及您在性能、复杂性和资源方面情愿做的掂量。
此外,成功您的缓存会带来乐趣并协助更好地理解像Redis这样的更复杂的产品。因此,咱们将在此文章中成功一个。
为什么咱们经常使用sync.Map
便捷地说,由于它完美地满足了咱们的须要。更深化的解释-sync.Map是Go规范库中的一个并发的、线程安保的map成功。它设计用于在多个goroutine并发访问映射的状况下经常使用,并且键的数量是未知的或随期间变动的。
值得留意的是,只管sync.Map是特定用例的一个很好的选用,但它并不象征着要交流一切场景的内置map类型。特意是,sync.Map最适宜以下状况:
在键的数量是固定的或事前知道的状况下,且映射可以预先调配,经常使用适当的同步如sync.Mutex或sync.RWMutex的内置map类型或许会提供更好的性能。
创立SafeCache
如上所述,咱们的SafeCache是一个便捷的、线程安保的缓存,经常使用Go的sync.Map存储其键值对。
首先,咱们定义一个CacheEntry结构来保管值及其过时期间戳:
typeCacheEntrystruct{valueinterface{}expirationint64}
在SafeCache结构中嵌入了一个sync.Map,它提供了对键值对的并发安保访问:
typeSafeCachestruct{syncMapsync.Map}
向缓存中增加值
而后咱们定义了一个Set方法,该方法准许咱们在缓存中存储一个带有指定生活期间(TTL,TimeToLive)的值。TTL选择了缓存条目应被以为有效的期间长度。一旦TTL过时,在下一个清算周期中将会移除该缓存条目。
func(sc*SafeCache)Set(keystring,valueinterface{},ttltime.Duration){expiration:=time.Now().Add(ttl).UnixNano()sc.syncMap.Store(key,CacheEntry{value:value,expiration:expiration})}
从缓存中检索值
接上去须要的方法是Get,它经常使用键从缓存中检索值。假设没有找到该值或该值已过时,该方法将前往false:
func(sc*SafeCache)Get(keystring)(interface{},bool){//...(seetheprovidedcodeforthefullimplementation)}
在Get方法中关键的是从缓存加载值后启动类型断言。咱们依赖于sync.Map的Load方法,该方法前往接口。
entry,found:=sc.syncMap.Load(key)if!found{returnnil,false}//TypeassertiontoCacheEntry,asentryisaninterface{}cacheEntry:=entry.(CacheEntry)
从缓存中移除值
当然,咱们还须要一个Delete方法,使咱们能够从缓存中移除一个值:
func(sc*SafeCache)Delete(keystring){sc.syncMap.Delete(key)}
清算过时条目
咱们经过CleanUp方法裁减了缓存,该方法担任活期从缓存中删除过时的条目。它经常使用sync.Map提供的Range方法遍历缓存中的一切键值对,并删除那些TTL已过时的条目:
func(sc*SafeCache)CleanUp(){//...(seetheprovidedcodeforthefullimplementation)}
要运转CleanUp方法,咱们可以在初始化缓存时启动一个独自的Goroutine:
cache:=&SafeCache{}gocache.CleanUp()
完整的代码片段
packagecacheimport("sync""time")//CacheEntryisavaluestoredinthecache.typeCacheEntrystruct{valueinterface{}expirationint64}//SafeCacheisathread-safecache.typeSafeCachestruct{syncMapsync.Map}//SetstoresavalueinthecachewithagivenTTL//(timetolive)inseconds.func(sc*SafeCache)Set(keystring,valueinterface{},ttltime.Duration){expiration:=time.Now().Add(ttl).UnixNano()sc.syncMap.Store(key,CacheEntry{value:value,expiration:expiration})}//Getretrievesavaluefromthecache.Ifthevalueisnotfound//orhasexpired,itreturnsfalse.func(sc*SafeCache)Get(keystring)(interface{},bool){entry,found:=sc.syncMap.Load(key)if!found{returnnil,false}//TypeassertiontoCacheEntry,asentryisaninterface{}cacheEntry:=entry.(CacheEntry)iftime.Now().UnixNano()>cacheEntry.expiration{sc.syncMap.Delete(key)returnnil,false}returncacheEntry.value,true}//Deleteremovesavaluefromthecache.func(sc*SafeCache)Delete(keystring){sc.syncMap.Delete(key)}//CleanUpperiodicallyremovesexpiredentriesfromthecache.func(sc*SafeCache)CleanUp(){for{time.Sleep(1*time.Minute)sc.syncMap.Range(func(key,entryinterface{})bool{cacheEntry:=entry.(CacheEntry)iftime.Now().UnixNano()>cacheEntry.expiration{sc.syncMap.Delete(key)}returntrue})}}
最后,你可以运转以下的mn.go程序来审核缓存能否上班。咱们创立了一个HTTP主机,它在/compute端点监听恳求。该主机接受一个整数n作为查问参数,并前往低廉计算的结果(在这种状况下,带有模拟提前的便捷平方操作)。主机首先审核缓存,看看给定输入的结果能否曾经被缓存;假设没有,它会计算结果,将其存储在缓存中,并将其前往给客户端。
要测试主机,运转代码并恳求。第一个恳求会破费更长的期间(由于模拟的提前),但具备相反n的后续恳求将立刻前往缓存的结果。
packagemainimport("fmt""log""/http""safe-cache/cache""strconv""time")funcexpensiveComputation(nint)int{//Simulateanexpensivecomputationtime.Sleep(2*time.Second)returnn*n}funcmain(){safeCache:=&cache.SafeCache{}//StartagoroutinetoperiodicallycleanupthecachegosafeCache.CleanUp()http.HandleFunc("/compute",func(whttp.ResponseWriter,r*http.Request){query:=r.URL.Query()n,err:=strconv.Atoi(query.Get("n"))iferr!=nil{http.Error(w,"Invalidinput",http.StatusBadRequest)return}cacheKey:=fmt.Sprintf("result_%d",n)cachedResult,found:=safeCache.Get(cacheKey)varresultintiffound{result=cachedResult.(int)}else{result=expensiveComputation(n)safeCache.Set(cacheKey,result,1*time.Minute)}_,err=fmt.Fprintf(w,"Result:%dn",result)iferr!=nil{return}})log.Fatal(http.ListenAndServe(":8080",nil))}
论断
在本文中,咱们展现了如何经常使用sync.Map包在Go中成功一个便捷、线程安保的缓存。
这个缓存成功支持基于TTL的过时的键值存储,并可以轻松地集成到你的Go运行中,以提高性能并缩小对你的数据源或计算资源的负载。
linux sync和sync使用哪个
不是windows中的保存 为了提高磁盘的读写效率,linux 会把频繁读写的磁盘文件在内存中做缓存。 。 但是这会造成数据的不同步, sync 就是为了数据同步。 。 (flush file system buffers)
C#程序运行时出现异常System.Runtime.InteropServices.COMException (0x80040154)
![成功线程安保的缓存](https://tyye.cn/zb_users/theme/tpure/style/images/lazyload.png)
当安装中缺失非托管同步组件(如 )时,发生此异常.当卸载了 Sync Framework 或安装未成功完成时,可能发生此问题.解决办法重新安装 Sync Framework.
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。