久久久精品一区ed2k-女人被男人叉到高潮的视频-中文字幕乱码一区久久麻豆樱花-俄罗斯熟妇真实视频

go語(yǔ)言怎么緩存 go語(yǔ)言緩存文件

golang sync.pool對(duì)象復(fù)用 并發(fā)原理 緩存池

在go http每一次go serve(l)都會(huì)構(gòu)建Request數(shù)據(jù)結(jié)構(gòu)。在大量數(shù)據(jù)請(qǐng)求或高并發(fā)的場(chǎng)景中,頻繁創(chuàng)建銷毀對(duì)象,會(huì)導(dǎo)致GC壓力。解決辦法之一就是使用對(duì)象復(fù)用技術(shù)。在http協(xié)議層之下,使用對(duì)象復(fù)用技術(shù)創(chuàng)建Request數(shù)據(jù)結(jié)構(gòu)。在http協(xié)議層之上,可以使用對(duì)象復(fù)用技術(shù)創(chuàng)建(w,*r,ctx)數(shù)據(jù)結(jié)構(gòu)。這樣即可以回快TCP層讀包之后的解析速度,也可也加快請(qǐng)求處理的速度。

成都創(chuàng)新互聯(lián)基于分布式IDC數(shù)據(jù)中心構(gòu)建的平臺(tái)為眾多戶提供簡(jiǎn)陽(yáng)服務(wù)器托管 四川大帶寬租用 成都機(jī)柜租用 成都服務(wù)器租用。

先上一個(gè)測(cè)試:

結(jié)論是這樣的:

貌似使用池化,性能弱爆了???這似乎與net/http使用sync.pool池化Request來(lái)優(yōu)化性能的選擇相違背。這同時(shí)也說(shuō)明了一個(gè)問(wèn)題,好的東西,如果濫用反而造成了性能成倍的下降。在看過(guò)pool原理之后,結(jié)合實(shí)例,將給出正確的使用方法,并給出預(yù)期的效果。

sync.Pool是一個(gè) 協(xié)程安全 的 臨時(shí)對(duì)象池 。數(shù)據(jù)結(jié)構(gòu)如下:

local 成員的真實(shí)類型是一個(gè) poolLocal 數(shù)組,localSize 是數(shù)組長(zhǎng)度。這涉及到Pool實(shí)現(xiàn),pool為每個(gè)P分配了一個(gè)對(duì)象,P數(shù)量設(shè)置為runtime.GOMAXPROCS(0)。在并發(fā)讀寫(xiě)時(shí),goroutine綁定的P有對(duì)象,先用自己的,沒(méi)有去偷其它P的。go語(yǔ)言將數(shù)據(jù)分散在了各個(gè)真正運(yùn)行的P中,降低了鎖競(jìng)爭(zhēng),提高了并發(fā)能力。

不要習(xí)慣性地誤認(rèn)為New是一個(gè)關(guān)鍵字,這里的New是Pool的一個(gè)字段,也是一個(gè)閉包名稱。其API:

如果不指定New字段,對(duì)象池為空時(shí)會(huì)返回nil,而不是一個(gè)新構(gòu)建的對(duì)象。Get()到的對(duì)象是隨機(jī)的。

原生sync.Pool的問(wèn)題是,Pool中的對(duì)象會(huì)被GC清理掉,這使得sync.Pool只適合做簡(jiǎn)單地對(duì)象池,不適合作連接池。

pool創(chuàng)建時(shí)不能指定大小,沒(méi)有數(shù)量限制。pool中對(duì)象會(huì)被GC清掉,只存在于兩次GC之間。實(shí)現(xiàn)是pool的init方法注冊(cè)了一個(gè)poolCleanup()函數(shù),這個(gè)方法在GC之前執(zhí)行,清空pool中的所有緩存對(duì)象。

為使多協(xié)程使用同一個(gè)POOL。最基本的想法就是每個(gè)協(xié)程,加鎖去操作共享的POOL,這顯然是低效的。而進(jìn)一步改進(jìn),類似于ConcurrentHashMap(JDK7)的分Segment,提高其并發(fā)性可以一定程度性緩解。

注意到pool中的對(duì)象是無(wú)差異性的,加鎖或者分段加鎖都不是較好的做法。go的做法是為每一個(gè)綁定協(xié)程的P都分配一個(gè)子池。每個(gè)子池又分為私有池和共享列表。共享列表是分別存放在各個(gè)P之上的共享區(qū)域,而不是各個(gè)P共享的一塊內(nèi)存。協(xié)程拿自己P里的子池對(duì)象不需要加鎖,拿共享列表中的就需要加鎖了。

Get對(duì)象過(guò)程:

Put過(guò)程:

如何解決Get最壞情況遍歷所有P才獲取得對(duì)象呢:

方法1止前sync.pool并沒(méi)有這樣的設(shè)置。方法2由于goroutine被分配到哪個(gè)P由調(diào)度器調(diào)度不可控,無(wú)法確保其平衡。

由于不可控的GC導(dǎo)致生命周期過(guò)短,且池大小不可控,因而不適合作連接池。僅適用于增加對(duì)象重用機(jī)率,減少GC負(fù)擔(dān)。2

執(zhí)行結(jié)果:

單線程情況下,遍歷其它無(wú)元素的P,長(zhǎng)時(shí)間加鎖性能低下。啟用協(xié)程改善。

結(jié)果:

測(cè)試場(chǎng)景在goroutines遠(yuǎn)大于GOMAXPROCS情況下,與非池化性能差異巨大。

測(cè)試結(jié)果

可以看到同樣使用*sync.pool,較大池大小的命中率較高,性能遠(yuǎn)高于空池。

結(jié)論:pool在一定的使用條件下提高并發(fā)性能,條件1是協(xié)程數(shù)遠(yuǎn)大于GOMAXPROCS,條件2是池中對(duì)象遠(yuǎn)大于GOMAXPROCS。歸結(jié)成一個(gè)原因就是使對(duì)象在各個(gè)P中均勻分布。

池pool和緩存cache的區(qū)別。池的意思是,池內(nèi)對(duì)象是可以互換的,不關(guān)心具體值,甚至不需要區(qū)分是新建的還是從池中拿出的。緩存指的是KV映射,緩存里的值互不相同,清除機(jī)制更為復(fù)雜。緩存清除算法如LRU、LIRS緩存算法。

池空間回收的幾種方式。一些是GC前回收,一些是基于時(shí)鐘或弱引用回收。最終確定在GC時(shí)回收Pool內(nèi)對(duì)象,即不回避GC。用java的GC解釋弱引用。GC的四種引用:強(qiáng)引用、弱引用、軟引用、虛引用。虛引用即沒(méi)有引用,弱引用GC但有空間則保留,軟引用GC即清除。ThreadLocal的值為弱引用的例子。

regexp 包為了保證并發(fā)時(shí)使用同一個(gè)正則,而維護(hù)了一組狀態(tài)機(jī)。

fmt包做字串拼接,從sync.pool拿[]byte對(duì)象。避免頻繁構(gòu)建再GC效率高很多。

(十一)golang 內(nèi)存分析

編寫(xiě)過(guò)C語(yǔ)言程序的肯定知道通過(guò)malloc()方法動(dòng)態(tài)申請(qǐng)內(nèi)存,其中內(nèi)存分配器使用的是glibc提供的ptmalloc2。 除了glibc,業(yè)界比較出名的內(nèi)存分配器有Google的tcmalloc和Facebook的jemalloc。二者在避免內(nèi)存碎片和性能上均比glic有比較大的優(yōu)勢(shì),在多線程環(huán)境中效果更明顯。

Golang中也實(shí)現(xiàn)了內(nèi)存分配器,原理與tcmalloc類似,簡(jiǎn)單的說(shuō)就是維護(hù)一塊大的全局內(nèi)存,每個(gè)線程(Golang中為P)維護(hù)一塊小的私有內(nèi)存,私有內(nèi)存不足再?gòu)娜稚暾?qǐng)。另外,內(nèi)存分配與GC(垃圾回收)關(guān)系密切,所以了解GC前有必要了解內(nèi)存分配的原理。

為了方便自主管理內(nèi)存,做法便是先向系統(tǒng)申請(qǐng)一塊內(nèi)存,然后將內(nèi)存切割成小塊,通過(guò)一定的內(nèi)存分配算法管理內(nèi)存。 以64位系統(tǒng)為例,Golang程序啟動(dòng)時(shí)會(huì)向系統(tǒng)申請(qǐng)的內(nèi)存如下圖所示:

預(yù)申請(qǐng)的內(nèi)存劃分為spans、bitmap、arena三部分。其中arena即為所謂的堆區(qū),應(yīng)用中需要的內(nèi)存從這里分配。其中spans和bitmap是為了管理arena區(qū)而存在的。

arena的大小為512G,為了方便管理把a(bǔ)rena區(qū)域劃分成一個(gè)個(gè)的page,每個(gè)page為8KB,一共有512GB/8KB個(gè)頁(yè);

spans區(qū)域存放span的指針,每個(gè)指針對(duì)應(yīng)一個(gè)page,所以span區(qū)域的大小為(512GB/8KB)乘以指針大小8byte = 512M

bitmap區(qū)域大小也是通過(guò)arena計(jì)算出來(lái),不過(guò)主要用于GC。

span是用于管理arena頁(yè)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu),每個(gè)span中包含1個(gè)或多個(gè)連續(xù)頁(yè),為了滿足小對(duì)象分配,span中的一頁(yè)會(huì)劃分更小的粒度,而對(duì)于大對(duì)象比如超過(guò)頁(yè)大小,則通過(guò)多頁(yè)實(shí)現(xiàn)。

根據(jù)對(duì)象大小,劃分了一系列class,每個(gè)class都代表一個(gè)固定大小的對(duì)象,以及每個(gè)span的大小。如下表所示:

上表中每列含義如下:

class: class ID,每個(gè)span結(jié)構(gòu)中都有一個(gè)class ID, 表示該span可處理的對(duì)象類型

bytes/obj:該class代表對(duì)象的字節(jié)數(shù)

bytes/span:每個(gè)span占用堆的字節(jié)數(shù),也即頁(yè)數(shù)乘以頁(yè)大小

objects: 每個(gè)span可分配的對(duì)象個(gè)數(shù),也即(bytes/spans)/(bytes/obj)waste

bytes: 每個(gè)span產(chǎn)生的內(nèi)存碎片,也即(bytes/spans)%(bytes/obj)上表可見(jiàn)最大的對(duì)象是32K大小,超過(guò)32K大小的由特殊的class表示,該class ID為0,每個(gè)class只包含一個(gè)對(duì)象。

span是內(nèi)存管理的基本單位,每個(gè)span用于管理特定的class對(duì)象, 跟據(jù)對(duì)象大小,span將一個(gè)或多個(gè)頁(yè)拆分成多個(gè)塊進(jìn)行管理。src/runtime/mheap.go:mspan定義了其數(shù)據(jù)結(jié)構(gòu):

以class 10為例,span和管理的內(nèi)存如下圖所示:

spanclass為10,參照class表可得出npages=1,nelems=56,elemsize為144。其中startAddr是在span初始化時(shí)就指定了某個(gè)頁(yè)的地址。allocBits指向一個(gè)位圖,每位代表一個(gè)塊是否被分配,本例中有兩個(gè)塊已經(jīng)被分配,其allocCount也為2。next和prev用于將多個(gè)span鏈接起來(lái),這有利于管理多個(gè)span,接下來(lái)會(huì)進(jìn)行說(shuō)明。

有了管理內(nèi)存的基本單位span,還要有個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)管理span,這個(gè)數(shù)據(jù)結(jié)構(gòu)叫mcentral,各線程需要內(nèi)存時(shí)從mcentral管理的span中申請(qǐng)內(nèi)存,為了避免多線程申請(qǐng)內(nèi)存時(shí)不斷的加鎖,Golang為每個(gè)線程分配了span的緩存,這個(gè)緩存即是cache。src/runtime/mcache.go:mcache定義了cache的數(shù)據(jù)結(jié)構(gòu)

alloc為mspan的指針數(shù)組,數(shù)組大小為class總數(shù)的2倍。數(shù)組中每個(gè)元素代表了一種class類型的span列表,每種class類型都有兩組span列表,第一組列表中所表示的對(duì)象中包含了指針,第二組列表中所表示的對(duì)象不含有指針,這么做是為了提高GC掃描性能,對(duì)于不包含指針的span列表,沒(méi)必要去掃描。根據(jù)對(duì)象是否包含指針,將對(duì)象分為noscan和scan兩類,其中noscan代表沒(méi)有指針,而scan則代表有指針,需要GC進(jìn)行掃描。mcache和span的對(duì)應(yīng)關(guān)系如下圖所示:

mchache在初始化時(shí)是沒(méi)有任何span的,在使用過(guò)程中會(huì)動(dòng)態(tài)的從central中獲取并緩存下來(lái),跟據(jù)使用情況,每種class的span個(gè)數(shù)也不相同。上圖所示,class 0的span數(shù)比class1的要多,說(shuō)明本線程中分配的小對(duì)象要多一些。

cache作為線程的私有資源為單個(gè)線程服務(wù),而central則是全局資源,為多個(gè)線程服務(wù),當(dāng)某個(gè)線程內(nèi)存不足時(shí)會(huì)向central申請(qǐng),當(dāng)某個(gè)線程釋放內(nèi)存時(shí)又會(huì)回收進(jìn)central。src/runtime/mcentral.go:mcentral定義了central數(shù)據(jù)結(jié)構(gòu):

lock: 線程間互斥鎖,防止多線程讀寫(xiě)沖突

spanclass : 每個(gè)mcentral管理著一組有相同class的span列表

nonempty: 指還有內(nèi)存可用的span列表

empty: 指沒(méi)有內(nèi)存可用的span列表

nmalloc: 指累計(jì)分配的對(duì)象個(gè)數(shù)線程從central獲取span步驟如下:

將span歸還步驟如下:

從mcentral數(shù)據(jù)結(jié)構(gòu)可見(jiàn),每個(gè)mcentral對(duì)象只管理特定的class規(guī)格的span。事實(shí)上每種class都會(huì)對(duì)應(yīng)一個(gè)mcentral,這個(gè)mcentral的集合存放于mheap數(shù)據(jù)結(jié)構(gòu)中。src/runtime/mheap.go:mheap定義了heap的數(shù)據(jù)結(jié)構(gòu):

lock: 互斥鎖

spans: 指向spans區(qū)域,用于映射span和page的關(guān)系

bitmap:bitmap的起始地址

arena_start: arena區(qū)域首地址

arena_used: 當(dāng)前arena已使用區(qū)域的最大地址

central: 每種class對(duì)應(yīng)的兩個(gè)mcentral

從數(shù)據(jù)結(jié)構(gòu)可見(jiàn),mheap管理著全部的內(nèi)存,事實(shí)上Golang就是通過(guò)一個(gè)mheap類型的全局變量進(jìn)行內(nèi)存管理的。mheap內(nèi)存管理示意圖如下:

系統(tǒng)預(yù)分配的內(nèi)存分為spans、bitmap、arean三個(gè)區(qū)域,通過(guò)mheap管理起來(lái)。接下來(lái)看內(nèi)存分配過(guò)程。

針對(duì)待分配對(duì)象的大小不同有不同的分配邏輯:

(0, 16B) 且不包含指針的對(duì)象: Tiny分配

(0, 16B) 包含指針的對(duì)象:正常分配

[16B, 32KB] : 正常分配

(32KB, -) : 大對(duì)象分配其中Tiny分配和大對(duì)象分配都屬于內(nèi)存管理的優(yōu)化范疇,這里暫時(shí)僅關(guān)注一般的分配方法。

以申請(qǐng)size為n的內(nèi)存為例,分配步驟如下:

Golang內(nèi)存分配是個(gè)相當(dāng)復(fù)雜的過(guò)程,其中還摻雜了GC的處理,這里僅僅對(duì)其關(guān)鍵數(shù)據(jù)結(jié)構(gòu)進(jìn)行了說(shuō)明,了解其原理而又不至于深陷實(shí)現(xiàn)細(xì)節(jié)。1、Golang程序啟動(dòng)時(shí)申請(qǐng)一大塊內(nèi)存并劃分成spans、bitmap、arena區(qū)域

2、arena區(qū)域按頁(yè)劃分成一個(gè)個(gè)小塊。

3、span管理一個(gè)或多個(gè)頁(yè)。

4、mcentral管理多個(gè)span供線程申請(qǐng)使用

5、mcache作為線程私有資源,資源來(lái)源于mcentral。

Go語(yǔ)言用什么緩存框架好,Redis嗎

你要的應(yīng)該是 Reids 或 Memcached 這些緩存服務(wù),在 Go 語(yǔ)言中的客戶端工具。

GitHub 上有個(gè) repo 叫 awesome-go(GitHub - avelino/awesome-go: A curated list of awesome Go frameworks, libraries and software),整理了常見(jiàn)的 Go 框架或代碼庫(kù),其中就有 Redis 和 Memcached 的客戶端。

網(wǎng)站題目:go語(yǔ)言怎么緩存 go語(yǔ)言緩存文件
標(biāo)題路徑:http://sd-ha.com/article48/hjdiep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、響應(yīng)式網(wǎng)站做網(wǎng)站、電子商務(wù)、Google、網(wǎng)站設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

微信小程序開(kāi)發(fā)