使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存的方法_第1頁
使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存的方法_第2頁
使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存的方法_第3頁
使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存的方法_第4頁
使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存的方法_第5頁
已閱讀5頁,還剩10頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存的方法目錄使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存由來Demo應(yīng)用字節(jié)VS結(jié)構(gòu)體Native緩存并發(fā)更新后臺(tái)更新同步過期緩存錯(cuò)誤故障轉(zhuǎn)移模式緩存?zhèn)鬏旀i競爭和底層性能內(nèi)存管理基準(zhǔn)測(cè)試開發(fā)者友好總結(jié)

使用Go實(shí)現(xiàn)健壯的內(nèi)存型緩存

本文介紹了緩存的常見使用場(chǎng)景、選型以及注意點(diǎn),比較有價(jià)值。

譯自:Implementingrobustin-memorycachewithGo

內(nèi)存型緩存是一種以消費(fèi)內(nèi)存為代價(jià)換取應(yīng)用性能和彈性的方式,同時(shí)也推遲了數(shù)據(jù)的一致性。在使用內(nèi)存型緩存時(shí)需要注意并行更新、錯(cuò)誤緩存、故障轉(zhuǎn)移、后臺(tái)更新、過期抖動(dòng),以及緩存預(yù)熱和轉(zhuǎn)換等問題。

由來

緩存是提升性能的最便捷的方式,但緩存不是萬能的,在某些場(chǎng)景下,由于事務(wù)或一致性的限制,你無法重復(fù)使用某個(gè)任務(wù)的結(jié)果。緩存失效是計(jì)算機(jī)科學(xué)中最常見的兩大難題之一。

如果將操作限制在不變的數(shù)據(jù)上,則無需擔(dān)心緩存失效。此時(shí)緩存僅用于減少網(wǎng)絡(luò)開銷。然而,如果需要與可變數(shù)據(jù)進(jìn)行同步,則必須關(guān)注緩存失效的問題。

最簡單的方式是基于TTL來設(shè)置緩存失效。雖然這種方式看起來遜于基于事件的緩存失效方式,但它簡單且可移植性高。由于無法保證事件能夠即時(shí)傳遞,因此在最壞的場(chǎng)景中(如事件代理短時(shí)間下線或過載),事件甚至還不如TTL精確。

短TTL通常是性能和一致性之間的一種折衷方式。它可以作為一道屏障來降低高流量下到數(shù)據(jù)源的負(fù)載。

Demo應(yīng)用

下面看一個(gè)簡單的demo應(yīng)用,它接收帶請(qǐng)求參數(shù)的URL,并根據(jù)請(qǐng)求參數(shù)返回一個(gè)JSON對(duì)象。由于數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫中,因此整個(gè)交互會(huì)比較慢。

下面將使用一個(gè)名為plt的工具對(duì)應(yīng)用進(jìn)行壓測(cè),plt包括參數(shù):

cardinality-生成的唯一的URLs的數(shù)據(jù),會(huì)影響到緩存命中率group-一次性發(fā)送的URL相似的請(qǐng)求個(gè)數(shù),模擬對(duì)相同鍵的并發(fā)訪問。

gorun./cmd/cplt--cardinality10000--group100--live-ui--duration10h--rate-limit5000curl--concurrency200-X'GET'':8008/helloname=Worldlocale=ru-RU'-H'accept:application/json'

上述命令會(huì)啟動(dòng)一個(gè)client,循環(huán)發(fā)送10000個(gè)不同的URLs,每秒發(fā)送5000個(gè)請(qǐng)求,最大并發(fā)數(shù)為200。每個(gè)URL會(huì)以100個(gè)請(qǐng)求為批次將進(jìn)行發(fā)送,用以模仿單個(gè)資源的并發(fā),下面展示了實(shí)時(shí)數(shù)據(jù):

Demo應(yīng)用通過CACHE環(huán)境變量定義了三種操作模式:

none:不使用緩存,所有請(qǐng)求都會(huì)涉及數(shù)據(jù)庫naive:使用簡單的map,TTL為3分鐘advanced:使用/bool64/cache庫,實(shí)現(xiàn)了很多特性來提升性能和彈性,TTL也是3分鐘。

Demo應(yīng)用的代碼位于:/vearutop/cache-story,可以使用makestart-depsrun命令啟動(dòng)demo應(yīng)用。

在不使用緩存的條件下,最大可以達(dá)到500RPS,在并發(fā)請(qǐng)求達(dá)到130之后DB開始因?yàn)門oomanyconnections而阻塞,這種結(jié)果不是最佳的,雖然并不嚴(yán)重,但需要提升性能。

使用advanced緩存的結(jié)果如下,吞吐量提升了60倍,并降低了請(qǐng)求延遲以及DB的壓力:

gorun./cmd/cplt--cardinality10000--group100--live-ui--duration10hcurl--concurrency100-X'GET'':8008/helloname=Worldlocale=ru-RU'-H'accept:application/json'

Requestspersecond:25064.03

Successfulrequests:15692025

Timespent:10m26.078s

Requestlatencypercentiles:

99%:28.22ms

95%:13.87ms

90%:9.77ms

50%:2.29ms

字節(jié)VS結(jié)構(gòu)體

哪個(gè)更佳?

取決于使用場(chǎng)景,字節(jié)緩存([]byte)的優(yōu)勢(shì)如下:

數(shù)據(jù)不可變,在訪問數(shù)據(jù)時(shí)需要進(jìn)行解碼由于內(nèi)存碎片較少,使用的內(nèi)存也較少對(duì)垃圾回收友好,因?yàn)闆]有什么需要遍歷的便于在線路上傳輸允許精確地限制內(nèi)存

字節(jié)緩存的最大劣勢(shì)是編解碼帶來的開銷,在熱點(diǎn)循環(huán)中,編解碼導(dǎo)致的開銷可能會(huì)非常大。

結(jié)構(gòu)體的優(yōu)勢(shì):

在訪問數(shù)據(jù)時(shí)無需進(jìn)行編碼/解碼更好地表達(dá)能力,可以緩存那些無法被序列化的內(nèi)容

結(jié)構(gòu)體緩存的劣勢(shì):

由于結(jié)構(gòu)體可以方便地進(jìn)行修改,因此可能會(huì)被無意間修改結(jié)構(gòu)體的內(nèi)存相對(duì)比較稀疏如果使用了大量長時(shí)間存在的結(jié)構(gòu)體,GC可能會(huì)花費(fèi)一定的時(shí)間進(jìn)行遍歷,來確保這些結(jié)構(gòu)體仍在使用中,因此會(huì)對(duì)GC采集器造成一定的壓力幾乎無法限制緩存實(shí)例的總內(nèi)存,動(dòng)態(tài)大小的項(xiàng)與其他所有項(xiàng)一起存儲(chǔ)在堆中。

本文使用了結(jié)構(gòu)體緩存。

Native緩存

使用了互斥鎖保護(hù)的map。當(dāng)需要檢索一個(gè)鍵的值時(shí),首先查看緩存中是否存在該數(shù)據(jù)以及有沒有過期,如果不存在,則需要從數(shù)據(jù)源構(gòu)造該數(shù)據(jù)并將其放到緩存中,然后返回給調(diào)用者。

整個(gè)邏輯比較簡單,但某些缺陷可能會(huì)導(dǎo)致嚴(yán)重的問題。

并發(fā)更新

當(dāng)多個(gè)調(diào)用者同時(shí)miss相同的鍵時(shí),它們會(huì)嘗試構(gòu)建數(shù)據(jù),這可能會(huì)導(dǎo)致死鎖或因?yàn)榫彺娌忍?dǎo)致資源耗盡。此外如果調(diào)用者嘗試構(gòu)建值,則會(huì)造成額外的延遲。

如果某些構(gòu)建失敗,即使緩存中可能存在有效的值,此時(shí)父調(diào)用者也會(huì)失敗。

可以使用低cardinality和高group來模擬上述問題:

gorun./cmd/cplt--cardinality100--group1000--live-ui--duration10h--rate-limit5000curl--concurrency150-X'GET'':8008/helloname=Worldlocale=ru-RU'-H'accept:application/json'

上圖展示了使用naive緩存的應(yīng)用,藍(lán)色標(biāo)志標(biāo)識(shí)重啟并使用advanced緩存??梢钥吹芥i嚴(yán)重影響了性能(IncomingRequestLatency)和資源使用(DBOperationRate)。

一種解決方案是阻塞并行構(gòu)建,這樣每次只能進(jìn)行一個(gè)構(gòu)建。但如果有大量并發(fā)調(diào)用者請(qǐng)求各種鍵,則可能會(huì)導(dǎo)致嚴(yán)重的鎖競爭。

更好的方式是對(duì)每個(gè)鍵的構(gòu)建單獨(dú)加鎖,這樣某個(gè)調(diào)用者就可以獲取鎖并執(zhí)行構(gòu)建,其他調(diào)用者則等待構(gòu)建好的值即可。

后臺(tái)更新

當(dāng)緩存過期時(shí),需要一個(gè)新的值,構(gòu)建新值可能會(huì)比較慢。如果同步進(jìn)行,則可以減慢尾部延遲(99%以上)??梢蕴崆皹?gòu)建那些被高度需要的緩存項(xiàng)(甚至在數(shù)據(jù)過期前)。如果可以容忍老數(shù)據(jù),也可以繼續(xù)使用這些數(shù)據(jù)。

這種場(chǎng)景下,可以使用老的/即將過期的數(shù)據(jù)提供服務(wù),并在后臺(tái)進(jìn)行更新。需要注意的是,如果構(gòu)建依賴父上下文,則在使用完老數(shù)據(jù)之后可能會(huì)取消上下文(如滿足父HTTP請(qǐng)求),如果我們使用這類上下文來訪問數(shù)據(jù),則會(huì)得到一個(gè)contextcanceled錯(cuò)誤。

解決方案是將上下文與父上下文進(jìn)行分離,并忽略父上下文的取消行為。

另外一種策略是主動(dòng)構(gòu)建那些即將過期的緩存項(xiàng),而無需父請(qǐng)求,但這樣可能會(huì)因?yàn)橐恢碧蕴切o人關(guān)心的緩存項(xiàng)而導(dǎo)致資源浪費(fèi)。

同步過期

假設(shè)啟動(dòng)了一個(gè)使用TTL緩存的實(shí)例,由于此時(shí)緩存是空的,所有請(qǐng)求都會(huì)導(dǎo)致緩存miss并創(chuàng)建值。這樣會(huì)導(dǎo)致數(shù)據(jù)源負(fù)載突增,每個(gè)保存的緩存項(xiàng)的過期時(shí)間都非常接近。一旦超過TTL,大部分緩存項(xiàng)幾乎會(huì)同步過期,這樣會(huì)導(dǎo)致一個(gè)新的負(fù)載突增,更新后的值也會(huì)有一個(gè)非常接近的過期時(shí)間,以此往復(fù)。

這種問題常見于熱點(diǎn)緩存項(xiàng),最終這些緩存項(xiàng)會(huì)同步更新,但需要花費(fèi)一段時(shí)間。

對(duì)這種問題的解決辦法是在過期時(shí)間上加抖動(dòng)。

如果過期抖動(dòng)為10%,意味著,過期時(shí)間為0.95*TTL到1.05*TTL。雖然這種抖動(dòng)幅度比較小,但也可以幫助降低同步過期帶來的問題。

下面例子中,使用高cardinality和高concurrency模擬這種情況。它會(huì)在短時(shí)間內(nèi)請(qǐng)求大量表項(xiàng),以此構(gòu)造過期峰值。

gorun./cmd/cplt--cardinality10000--group1--live-ui--duration10h--rate-limit5000curl--concurrency200-X'GET'':8008/helloname=Worldlocale=ru-RU'-H'accept:application/json'

從上圖可以看出,使用naive緩存無法避免同步過期問題,藍(lán)色標(biāo)識(shí)符表示重啟服務(wù)并使用帶10%抖動(dòng)的advanced緩存,可以看到降低了峰值,且整體服務(wù)更加穩(wěn)定。

緩存錯(cuò)誤

當(dāng)構(gòu)建值失敗,最簡單的方式就是將錯(cuò)誤返回給調(diào)用者即可,但這種方式可能會(huì)導(dǎo)致嚴(yán)重的問題。

例如,當(dāng)服務(wù)正常工作時(shí)可以借助緩存處理10K的RPS,但突然出現(xiàn)緩存構(gòu)建失敗(可能由于短時(shí)間內(nèi)數(shù)據(jù)庫過載、網(wǎng)絡(luò)問題或如錯(cuò)誤校驗(yàn)等邏輯錯(cuò)誤),此時(shí)所有的10KRPS都會(huì)命中數(shù)據(jù)源(因?yàn)榇藭r(shí)沒有緩存)。

對(duì)于高負(fù)載系統(tǒng),使用較短的TTL來緩存錯(cuò)誤至關(guān)重要。

故障轉(zhuǎn)移模式

有時(shí)使用過期的數(shù)據(jù)要好于直接返回錯(cuò)誤,特別是當(dāng)這些數(shù)據(jù)剛剛過期,這類數(shù)據(jù)有很大概率等于后續(xù)更新的數(shù)據(jù)。

故障轉(zhuǎn)移以精確性來換取彈性,通常是分布式系統(tǒng)中的一種折衷方式。

緩存?zhèn)鬏?/p>

緩存有相關(guān)的數(shù)據(jù)時(shí)效果最好。

當(dāng)啟動(dòng)一個(gè)新的實(shí)例時(shí),緩存是空的。由于產(chǎn)生有用的數(shù)據(jù)需要花費(fèi)一定的時(shí)間,因此這段時(shí)間內(nèi),緩存效率會(huì)大大降低。

有一些方式可以解決冷緩存帶來的問題。如可以通過遍歷數(shù)據(jù)來預(yù)熱那些可能有用的數(shù)據(jù)。

例如可以從數(shù)據(jù)庫表中拉取最近使用的內(nèi)容,并將其保存到緩存中。這種方式比較復(fù)雜,且并不一定能夠生效。

此外還可以通過定制代碼來決定使用哪些數(shù)據(jù)并在緩存中重構(gòu)這些表項(xiàng)。但這樣可能會(huì)對(duì)數(shù)據(jù)庫造成一定的壓力。

還可以通過共享緩存實(shí)例(如redis或memcached)來規(guī)避這種問題,但這也帶來了另一種問題,通過網(wǎng)絡(luò)讀取數(shù)據(jù)要遠(yuǎn)慢于從本地緩存讀取數(shù)據(jù)。此外,網(wǎng)絡(luò)帶寬也可能成為性能瓶頸,網(wǎng)絡(luò)數(shù)據(jù)的編解碼也增加了延遲和資源損耗。

最簡單的辦法是將緩存從活動(dòng)的實(shí)例傳輸?shù)叫聠?dòng)的實(shí)例中。

活動(dòng)實(shí)例緩存的數(shù)據(jù)具有高度相關(guān)性,因?yàn)檫@些數(shù)據(jù)是響應(yīng)真實(shí)用戶請(qǐng)求時(shí)產(chǎn)生的。

傳輸緩存并不需要重構(gòu)數(shù)據(jù),因此不會(huì)濫用數(shù)據(jù)源。

在生產(chǎn)系統(tǒng)中,通常會(huì)并行多個(gè)應(yīng)用實(shí)例。在部署過程中,這些實(shí)例會(huì)被順序重啟,因此總有一個(gè)實(shí)例是活動(dòng)的,且具有高質(zhì)量的緩存。

Go有一個(gè)內(nèi)置的二進(jìn)制系列化格式encoding/gob,它可以幫助以最小的代價(jià)來傳輸數(shù)據(jù),缺點(diǎn)是這種方式使用了反射,且需要暴露字段。

使用緩存?zhèn)鬏數(shù)牧硪粋€(gè)注意事項(xiàng)是不同版本的應(yīng)用可能有不兼容的數(shù)據(jù)結(jié)構(gòu),為了解決這種問題,需要為緩存的結(jié)構(gòu)添加指紋,并在不一致時(shí)停止傳輸。

下面是一個(gè)簡單的實(shí)現(xiàn):

//RecursiveTypeHashhashestypeofvaluerecursivelytoensurestructuralmatch.

funcrecursiveTypeHash(treflect.Type,hhash.Hash64,metmap[reflect.Type]bool){

for{

ift.Kind()!=reflect.Ptr{

break

t=t.Elem()

ifmet[t]{

return

met[t]=true

switcht.Kind(){

casereflect.Struct:

fori:=0;it.NumField();i++{

f:=t.Field(i)

//Skipunexportedfield.

iff.Name!=""(f.Name[0:1]==strings.ToLower(f.Name[0:1])){

continue

if!f.Anonymous{

_,_=h.Write([]byte(f.Name))

recursiveTypeHash(f.Type,h,met)

casereflect.Slice,reflect.Array:

recursiveTypeHash(t.Elem(),h,met)

casereflect.Map:

recursiveTypeHash(t.Key(),h,met)

recursiveTypeHash(t.Elem(),h,met)

default:

_,_=h.Write([]byte(t.String()))

}

可以通過HTTP或其他合適的協(xié)議來傳輸緩存數(shù)據(jù),本例中使用了HTTP,代碼為/debug/transfer-cache。注意,緩存可能會(huì)包含不應(yīng)該對(duì)外暴露的敏感信息。

在本例中,可以借助于單個(gè)啟用了不同端口的應(yīng)用程序?qū)嵗齺韴?zhí)行傳輸:

CACHE_TRANSFER_URL=:8008/debug/transfer-cacheHTTP_LISTEN_ADDR=:8009gorunmain.go

2025-05-09T02:33:42.871+0200INFOcache/http.go:282cacherestored{"processed":10000,"elapsed":"12.963942ms","speed":"39.564084MB/s","bytes":537846}

2025-05-09T02:33:42.874+0200INFObrick/http.go:66startingserver,SwaggerUIat:8009/docs

2025-05-09T02:34:01.162+0200INFOcache/http.go:175cachedumpfinished{"processed":10000,"elapsed":"12.654621ms","bytes":537846,"speed":"40.530944MB/s","name":"greetings","trace.id":"31aeeb8e9e622b3cd3e1aa29fa3334af","transaction.id":"a0e8d90542325ab4"}

上圖中藍(lán)色標(biāo)識(shí)標(biāo)識(shí)應(yīng)用重啟,最后兩條為緩存?zhèn)鬏?。可以看到性能不受影響,而在沒有緩存?zhèn)鬏數(shù)那闆r下,會(huì)受到嚴(yán)重的預(yù)熱懲罰。

一個(gè)不那么明顯的好處是,可以將緩存數(shù)據(jù)傳輸?shù)奖镜亻_發(fā)機(jī)器,用于重現(xiàn)和調(diào)試生產(chǎn)環(huán)境的問題。

鎖競爭和底層性能

基本每種緩存實(shí)現(xiàn)都會(huì)使用鍵值映射來支持并發(fā)訪問(通常是讀)。

大多數(shù)場(chǎng)景下可以忽略底層性能帶來的影響。例如,如果使用內(nèi)存型緩存來處理HTTPAPI,使用最簡單的map+mutex就足夠了,這是因?yàn)镮O操作所需的時(shí)間要遠(yuǎn)大于內(nèi)存操作。記住這一點(diǎn)很重要,以免過早地進(jìn)行優(yōu)化以及增加不合理的復(fù)雜性。

如果依賴內(nèi)存型緩存的應(yīng)用是CPU密集型的,此時(shí)鎖競爭可能會(huì)影響到整體性能。

為了避免并發(fā)讀寫下的數(shù)據(jù)沖突,可能會(huì)引入鎖競爭。在使用單個(gè)互斥鎖的情況下,這種同步可能會(huì)限制同一時(shí)間內(nèi)只能進(jìn)行一個(gè)操作,這也意味著多核CPU可能無法發(fā)揮作用。

對(duì)于以讀為主的負(fù)載,標(biāo)準(zhǔn)的sync.Map就可以滿足性能要求,但對(duì)于以寫為主的負(fù)載,則會(huì)降低其性能。有一種比sync.Map性能更高的方式/puzpuzpuz/xsync.Map,它使用了Cache-LineHashTable(CLHT)數(shù)據(jù)結(jié)構(gòu)。

另一種常見的方式是通過map分片的方式(fastcache,bigcache,bool64/cache)來降低鎖競爭,這種方式基于鍵將值分散到不同的桶中,在易用性和性能之間做了折衷。

內(nèi)存管理

內(nèi)存是一個(gè)有限的資源,因此緩存不能無限增長。

過期的元素需要從緩存中淘汰,這個(gè)步驟可以同步執(zhí)行,也可以在后臺(tái)執(zhí)行。使用后臺(tái)回收方式不會(huì)阻塞應(yīng)用本身,且如果將后臺(tái)回收進(jìn)程配置為延遲回收的方式時(shí),在需要故障轉(zhuǎn)移時(shí)就可以使用過期的數(shù)據(jù)。

如果上述淘汰過期數(shù)據(jù)的方式無法滿足內(nèi)存回收的要求,可以考慮使用其他淘汰策略。在選擇淘汰策略時(shí)需要平衡CPU/內(nèi)存使用和命中/丟失率??傊?,淘汰的目的是為了在可接受的性能預(yù)算內(nèi)優(yōu)化命中/丟失率,這也是評(píng)估一個(gè)淘汰策略時(shí)需要注意的指標(biāo)。

下面是常見的選擇淘汰策略的原則:

最近最少頻率使用(LFU),需要在每次訪問時(shí)維護(hù)計(jì)數(shù)器最近最少使用(LRU),需要在每次訪問時(shí)更新元素的時(shí)間戳或順序先進(jìn)先出(FIFO),一旦創(chuàng)建緩存就可以使用緩存中的數(shù)據(jù),比較輕量隨機(jī)元素,性能最佳,不需要任何排序,但精確性最低

上述給出了如何選項(xiàng)一個(gè)淘汰策略,下一個(gè)問題是何時(shí)以及應(yīng)該淘汰多少元素?。

對(duì)于[]byte緩存來說,該問題比較容易解決,因?yàn)榇蠖鄶?shù)實(shí)現(xiàn)中都精確提供了控制內(nèi)存的方式。

但對(duì)于結(jié)構(gòu)體緩存來說就比較棘手了。在應(yīng)用執(zhí)行過程中,很難可靠地確定特定結(jié)構(gòu)體對(duì)堆內(nèi)存的影響,GC可能會(huì)獲取到這些內(nèi)存信息,但應(yīng)用本身則無法獲取。下面兩種獲取結(jié)構(gòu)體內(nèi)存的指標(biāo)精確度不高,但可用:

緩存中的元素個(gè)數(shù)應(yīng)用使用的總內(nèi)存

由于這些指標(biāo)并不與使用的緩存內(nèi)存成線性比例,因此不能據(jù)此計(jì)算需要淘汰的元素。一種比較合適的方式是在觸發(fā)淘汰時(shí),淘汰一部分元素(如占使用內(nèi)存10%的元素)。

緩存數(shù)據(jù)的堆影響很大程度上與映射實(shí)現(xiàn)有關(guān)??梢詮南旅娴男阅軠y(cè)試中看到,相比于二進(jìn)制序列化(未壓縮)的數(shù)據(jù),map[string]struct{...}占用的內(nèi)存是前者的4倍。

基準(zhǔn)測(cè)試

下面是保存1M小結(jié)構(gòu)體(struct{int,bool,string})的基準(zhǔn)測(cè)試,驗(yàn)證包括10%的讀操作以及0.1%的寫操作。字節(jié)緩存通過編解碼結(jié)構(gòu)體來驗(yàn)證。

goos:darwin

goarch:amd64

cpu:Intel(R)Core(TM)i7-9750HCPU@2.60GHz

nameMB/inusetime/op(10%)time/op(0.1%)

sync.Map192±0%142ns±4%29.8ns±10%//Greatforread-heavyworkloads.

shardedMap196±0%53.3ns±3%28.4ns±11%

mutexMap182±0%226ns±3%207ns±1%

rwMutexMap182±0%233ns±2%67.8ns±2%//RWMutexperfdegradeswithmorewrites.

shardedMapOf181±0%50.3ns±3%27.3ns±13%

ristretto346±0%167ns±8%54.1ns±4%//Failedtokeepfullworkingset,~7-15%oftheitemsareevicted.

xs

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論