成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Gosync.Pool的原理及作用是什么

本篇內(nèi)容主要講解“Go sync.Pool的原理及作用是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Go sync.Pool的原理及作用是什么”吧!

為莊河等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及莊河網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站建設(shè)、成都網(wǎng)站制作、莊河網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

使用方式

sync.Pool 使用很簡(jiǎn)單,但是想用對(duì)卻很麻煩,因?yàn)槟阌锌赡芸吹骄W(wǎng)上一堆錯(cuò)誤的示例,各位同學(xué)在搜索 sync.Pool 的使用例子時(shí),要特別注意。

sync.Pool 是一個(gè)內(nèi)存池。通常內(nèi)存池是用來(lái)防止內(nèi)存泄露的(例如C/C++)。sync.Pool 這個(gè)內(nèi)存池卻不是干這個(gè)的,帶 GC 功能的語(yǔ)言都存在垃圾回收 STW 問(wèn)題,需要回收的內(nèi)存塊越多,STW 持續(xù)時(shí)間就越長(zhǎng)。如果能讓 new 出來(lái)的變量,一直不被回收,得到重復(fù)利用,是不是就減輕了 GC 的壓力。

正確的使用示例(下面的demo選自gin)

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {    c := engine.pool.Get().(*Context)
    c.writermem.reset(w)
    c.Request = req
    c.reset()

    engine.handleHTTPRequest(c)

    engine.pool.Put(c)}

一定要注意的是:是先 Get 獲取內(nèi)存空間,基于這個(gè)內(nèi)存做相關(guān)的處理,然后再將這個(gè)內(nèi)存還回(Put)到 sync.Pool。

Pool 結(jié)構(gòu)

Go sync.Pool的原理及作用是什么

sync.Pool 全景圖

源碼圖解

Go sync.Pool的原理及作用是什么

Pool.Get

Go sync.Pool的原理及作用是什么

Pool.Put

簡(jiǎn)單點(diǎn)可以總結(jié)成下面的流程:

Go sync.Pool的原理及作用是什么

Pool.Get 流程

Go sync.Pool的原理及作用是什么

Pool.Put流程

Go sync.Pool的原理及作用是什么

Pool GC 流程

Sync.Pool 梳理

Pool 的內(nèi)容會(huì)清理?清理會(huì)造成數(shù)據(jù)丟失嗎?

Go 會(huì)在每個(gè) GC 周期內(nèi)定期清理 sync.Pool 內(nèi)的數(shù)據(jù)。

要分幾個(gè)方面來(lái)說(shuō)這個(gè)問(wèn)題。

  1. 已經(jīng)從 sync.Pool Get 的值,在 poolClean 時(shí)雖說(shuō)將 pool.local 置成了nil,Get 到的值依然是有效的,是被 GC 標(biāo)記為黑色的,不會(huì)被 GC回收,當(dāng) Put 后又重新加入到 sync.Pool 中

  2. 在第一個(gè) GC 周期內(nèi) Put 到 sync.Pool 的數(shù)值,在第二個(gè) GC 周期沒(méi)有被 Get 使用,就會(huì)被放在 local.victim 中。如果在 第三個(gè) GC 周期仍然沒(méi)有被使用就會(huì)被 GC 回收。

runtime.GOMAXPROCS 與 pool 之間的關(guān)系?

s := p.localSize
l := p.localif uintptr(pid) < s {
    return indexLocal(l, pid), pid
}if p.local == nil {
    allPools = append(allPools, p)
}// If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.size := runtime.GOMAXPROCS(0)
local := make([]poolLocal, size)
atomic.StorePointer(&p.local, unsafe.Pointer(&local[0])) // store-releaseruntime_StoreReluintptr(&p.localSize, uintptr(size))     // store-release

runtime.GOMAXPROCS(0) 是獲取當(dāng)前最大的 p 的數(shù)量。sync.Pool 的 poolLocal 數(shù)量受 p 的數(shù)量影響,會(huì)開(kāi)辟 runtime.GOMAXPROCS(0) 個(gè) poolLocal。某些場(chǎng)景下我們會(huì)使用 runtime.GOMAXPROCS(N) 來(lái)改變 p 的數(shù)量,會(huì)使 sync.Pool 的 pool.poolLocal 釋放重新開(kāi)辟新的空間。

為什么要開(kāi)辟 runtime.GOMAXPROCS 個(gè) local?

pool.local 是個(gè) poolLocal 結(jié)構(gòu),這個(gè)結(jié)構(gòu)體是 private + shared鏈表組成,在多 goroutine 的 Get/Put 下是有數(shù)據(jù)競(jìng)爭(zhēng)的,如果只有一個(gè) local 就需要加鎖來(lái)操作。每個(gè) p 的 local 就能減少加鎖造成的數(shù)據(jù)競(jìng)爭(zhēng)問(wèn)題。

New() 的作用?假如沒(méi)有 New 會(huì)出現(xiàn)什么情況?

從上面的 pool.Get 流程圖可以看出來(lái),從 sync.Pool 獲取一個(gè)內(nèi)存會(huì)嘗試從當(dāng)前 private,shared,其他的 p 的 shared 獲取或者 victim 獲取,如果實(shí)在獲取不到時(shí),才會(huì)調(diào)用 New 函數(shù)來(lái)獲取。也就是 New() 函數(shù)才是真正開(kāi)辟內(nèi)存空間的。New() 開(kāi)辟出來(lái)的的內(nèi)存空間使用完畢后,調(diào)用 pool.Put 函數(shù)放入到 sync.Pool 中被重復(fù)利用。

如果 New 函數(shù)沒(méi)有被初始化會(huì)怎樣呢?很明顯,sync.Pool 就廢掉了,因?yàn)闆](méi)有了初始化內(nèi)存的地方了。

先 Put,再 Get 會(huì)出現(xiàn)什么情況?

「一定要注意,下面這個(gè)例子的用法是錯(cuò)誤的」

func main(){
    pool:= sync.Pool{
        New: func() interface{} {
            return item{}
        },
    }
    pool.Put(item{value:1})
    data := pool.Get()
    fmt.Println(data)
}

如果你直接跑這個(gè)例子,能得到你想像的結(jié)果,但是在某些情況下就不是這個(gè)結(jié)果了。

在 Pool.Get 注釋里面有這么一句話:“Callers should not assume any relation between values passed to Put and the values returned by Get.”,告訴我們不能把值 Pool.Put 到 sync.Pool 中,再使用 Pool.Get 取出來(lái),因?yàn)?sync.Pool 不是 map 或者 slice,放入的值是有可能拿不到的,sync.Pool 的數(shù)據(jù)結(jié)構(gòu)就不支持做這個(gè)事情。

前面說(shuō)使用 sync.Pool 容易被錯(cuò)誤示例誤導(dǎo),就是上面這個(gè)寫(xiě)法。為什么 Put 的值 再 Get 會(huì)出現(xiàn)問(wèn)題?

  • 情況1:sync.Pool 的 poolCleanup 函數(shù)在系統(tǒng) GC 時(shí)會(huì)被調(diào)用,Put 到 sync.Pool 的值,由于有可能一直得不到利用,被在某個(gè) GC 周期內(nèi)就有可能被釋放掉了。

  • 情況2:不同的 goroutine 綁定的 p 有可能是不一樣的,當(dāng)前 p 對(duì)應(yīng)的 goroutine 放入到 sync.Pool 的值有可能被其他的 p 對(duì)應(yīng)的 goroutine 取到,導(dǎo)致當(dāng)前 goroutine 再也取不到這個(gè)值。

  • 情況3:使用 runtime.GOMAXPROCS(N) 來(lái)改變 p 的數(shù)量,會(huì)使 sync.Pool 的 pool.poolLocal 釋放重新開(kāi)辟新的空間,導(dǎo)致 sync.Pool 被釋放掉。

  • 情況4:還有很多情況

只 Get 不 Put 會(huì)內(nèi)存泄露嗎?

使用其他的池,如連接池,如果取連接使用后不放回連接池,就會(huì)出現(xiàn)連接池泄露,「是不是 sync.Pool 也有這個(gè)問(wèn)題呢?」

通過(guò)上面的流程圖,可以看出來(lái) Pool.Get 的時(shí)候會(huì)嘗試從當(dāng)前 private,shared,其他的 p 的 shared 獲取或者 victim 獲取,如果實(shí)在獲取不到時(shí),才會(huì)調(diào)用 New 函數(shù)來(lái)獲取,New 出來(lái)的內(nèi)容本身還是受系統(tǒng) GC 來(lái)控制的。所以如果我們提供的 New 實(shí)現(xiàn)不存在內(nèi)存泄露的話,那么 sync.Pool 是不會(huì)內(nèi)存泄露的。當(dāng) New 出來(lái)的變量如果不再被使用,就會(huì)被系統(tǒng) GC 給回收掉。

如果不 Put 回 sync.Pool,會(huì)造成 Get 的時(shí)候每次都調(diào)用的 New 來(lái)從堆棧申請(qǐng)空間,達(dá)不到減輕 GC 壓力。

使用場(chǎng)景

上面說(shuō)到 sync.Pool 業(yè)務(wù)開(kāi)發(fā)中不是一個(gè)常用結(jié)構(gòu),我們業(yè)務(wù)開(kāi)發(fā)中沒(méi)必要假想某塊代碼會(huì)有強(qiáng)烈的性能問(wèn)題,一上來(lái)就用 sync.Pool 硬懟。sync.Pool 主要是為了解決 Go GC 壓力過(guò)大問(wèn)題的,所以一般情況下,當(dāng)線上高并發(fā)業(yè)務(wù)出現(xiàn) GC 問(wèn)題需要被優(yōu)化時(shí),才需要用 sync.Pool 出場(chǎng)。

使用注意點(diǎn)

  1. sync.Pool 同樣不能被復(fù)制。

  2. 好的使用習(xí)慣,從 pool.Get 出來(lái)的值進(jìn)行數(shù)據(jù)的清空(reset),防止垃圾數(shù)據(jù)污染。

?  

本文基于的 Go 源碼版本:1.16.2

?

參考鏈接

  1. 深度解密 Go 語(yǔ)言之 sync.Pool https://www.cnblogs.com/qcrao-2018/p/12736031.html

  2. 請(qǐng)問(wèn)sync.Pool有什么缺點(diǎn)? https://mp.weixin.qq.com/s/2ZC1BWTylIZMmuQ3HwrnUg

  3. Go 1.13中 sync.Pool 是如何優(yōu)化的? https://colobu.com/2019/10/08/how-is-sync-Pool-improved-in-Go-1-13/

到此,相信大家對(duì)“Go sync.Pool的原理及作用是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

新聞標(biāo)題:Gosync.Pool的原理及作用是什么
轉(zhuǎn)載注明:http://jinyejixie.com/article38/jjhjpp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、App設(shè)計(jì)云服務(wù)器、服務(wù)器托管、電子商務(wù)、動(dòng)態(tài)網(wǎng)站

廣告

聲明:本網(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)

外貿(mào)網(wǎng)站制作
龙岩市| 武强县| 平谷区| 金平| 历史| 吉林市| 泸西县| 房产| 彰化市| 滦平县| 陈巴尔虎旗| 正宁县| 涞水县| 迭部县| 鄯善县| 山丹县| 甘洛县| 县级市| 镇雄县| 唐河县| 东丰县| 滦平县| 惠东县| 梅河口市| 商都县| 无为县| 长武县| 宝山区| 达孜县| 永新县| 龙陵县| 海宁市| 慈利县| 清涧县| 邢台县| 调兵山市| 南漳县| 合水县| 岳池县| 中宁县| 南充市|