婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 7分鐘讀懂Go的臨時對象池pool以及其應用場景

7分鐘讀懂Go的臨時對象池pool以及其應用場景

熱門標簽:浙江高速公路地圖標注 江西轉化率高的羿智云外呼系統 南通如皋申請開通400電話 學海導航地圖標注 西部云谷一期地圖標注 地圖標注的汽車標 中國地圖標注省會高清 高德地圖標注口訣 廣州呼叫中心外呼系統

臨時對象池 pool 是啥?

sync.Pool 給了一大段注釋來說明 pool 是啥,我們看看這段都說了些什么。

臨時對象池是一些可以分別存儲和取出的臨時對象。

池中的對象會在沒有任何通知的情況下被移出(釋放或者重新取出使用)。如果 pool 中持有某個對象的唯一引用,則該對象很可能會被回收。

Pool 在多 goroutine 使用環境中是安全的。

Pool 是用來緩存已經申請了的 目前未使用的 接下來可能會使用的 內存,以此緩解 GC 壓力。使用它可以方便高效的構建線程安全的 free list(一種用于動態內存申請的數據結構)。然而,它并不適合所有場景的 free list。

在同一 package 中獨立運行的多個獨立線程之間靜默共享一組臨時元素才是 pool 的合理使用場景。Pool 提供在多個獨立 client 之間共享臨時元素的機制。

在 fmt 包中有一個使用 Pool 的例子,它維護了一個動態大小的輸出 buffer。

另外,一些短生命周期的對象不適合使用 pool 來維護,這種情況下使用 pool 不劃算。這是應該使用它們自己的 free list(這里可能指的是 go 內存模型中用于緩存 32k小對象的 free list) 更高效。

Pool 一旦使用,不能被復制。

Pool 結構體的定義為:

type Pool struct {
 noCopy noCopy

 local  unsafe.Pointer // 本地P緩存池指針
 localSize uintptr  // 本地P緩存池大小

 // 當池中沒有可能對象時
 // 會調用 New 函數構造構造一個對象
 New func() interface{}
}

Pool 中有兩個定義的公共方法,分別是 Put - 向池中添加元素;Get - 從池中獲取元素,如果沒有,則調用 New 生成元素,如果 New 未設置,則返回 nil。

Get

Pool 會為每個 P 維護一個本地池,P 的本地池分為 私有池 private 和共享池 shared。私有池中的元素只能本地 P 使用,共享池中的元素可能會被其他 P 偷走,所以使用私有池 private 時不用加鎖,而使用共享池 shared 時需加鎖。

Get 會優先查找本地 private,再查找本地 shared,最后查找其他 P 的 shared,如果以上全部沒有可用元素,最后會調用 New 函數獲取新元素。

func (p *Pool) Get() interface{} {
 if race.Enabled {
  race.Disable()
 }
 // 獲取本地 P 的 poolLocal 對象
 l := p.pin() 
 
 // 先獲取 private 池中的對象(只有一個)
 x := l.private
 l.private = nil
 runtime_procUnpin()
 if x == nil {
  // 查找本地 shared 池,
  // 本地 shared 可能會被其他 P 訪問
  // 需要加鎖
  l.Lock()
  last := len(l.shared) - 1
  if last >= 0 {
   x = l.shared[last]
   l.shared = l.shared[:last]
  }
  l.Unlock()
  
  // 查找其他 P 的 shared 池
  if x == nil {
   x = p.getSlow()
  }
 }
 if race.Enabled {
  race.Enable()
  if x != nil {
   race.Acquire(poolRaceAddr(x))
  }
 }
 // 未找到可用元素,調用 New 生成
 if x == nil  p.New != nil {
  x = p.New()
 }
 return x
}

getSlow,從其他 P 中的 shared 池中獲取可用元素:

func (p *Pool) getSlow() (x interface{}) {
 // See the comment in pin regarding ordering of the loads.
 size := atomic.LoadUintptr(p.localSize) // load-acquire
 local := p.local       // load-consume
 // Try to steal one element from other procs.
 pid := runtime_procPin()
 runtime_procUnpin()
 for i := 0; i  int(size); i++ {
  l := indexLocal(local, (pid+i+1)%int(size))
  // 對應 pool 需加鎖
  l.Lock()
  last := len(l.shared) - 1
  if last >= 0 {
   x = l.shared[last]
   l.shared = l.shared[:last]
   l.Unlock()
   break
  }
  l.Unlock()
 }
 return x
}

Put

Put 優先把元素放在 private 池中;如果 private 不為空,則放在 shared 池中。有趣的是,在入池之前,該元素有 1/4 可能被丟掉。

func (p *Pool) Put(x interface{}) {
 if x == nil {
  return
 }
 if race.Enabled {
  if fastrand()%4 == 0 {
   // 隨機把元素扔掉...
   // Randomly drop x on floor.
   return
  }
  race.ReleaseMerge(poolRaceAddr(x))
  race.Disable()
 }
 l := p.pin()
 if l.private == nil {
  l.private = x
  x = nil
 }
 runtime_procUnpin()
 if x != nil {
  // 共享池訪問,需要加鎖
  l.Lock()
  l.shared = append(l.shared, x)
  l.Unlock()
 }
 if race.Enabled {
  race.Enable()
 }
}

poolCleanup

當世界暫停,垃圾回收將要開始時, poolCleanup 會被調用。該函數內不能分配內存且不能調用任何運行時函數。原因:
防止錯誤的保留整個 Pool

如果 GC 發生時,某個 goroutine 正在訪問 l.shared,整個 Pool 將會保留,下次執行時將會有雙倍內存

func poolCleanup() { 
 for i, p := range allPools {
  allPools[i] = nil
  for i := 0; i  int(p.localSize); i++ {
   l := indexLocal(p.local, i)
   l.private = nil
   for j := range l.shared {
   l.shared[j] = nil
   }
   l.shared = nil
  }
  p.local = nil
  p.localSize = 0
 }
 allPools = []*Pool{}
}

案例1:gin 中的 Context pool

在 web 應用中,后臺在處理用戶的每條請求時都會為當前請求創建一個上下文環境 Context,用于存儲請求信息及相應信息等。Context 滿足長生命周期的特點,且用戶請求也是屬于并發環境,所以對于線程安全的 Pool 非常適合用來維護 Context 的臨時對象池。

Gin 在結構體 Engine 中定義了一個 pool:

type Engine struct {
 // ... 省略了其他字段
 pool    sync.Pool
}

初始化 engine 時定義了 pool 的 New 函數:

engine.pool.New = func() interface{} {
 return engine.allocateContext()
}

// allocateContext
func (engine *Engine) allocateContext() *Context {
 // 構造新的上下文對象
 return Context{engine: engine}
}

ServeHttp:

// 從 pool 中獲取,并轉化為 *Context
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset() // reset

engine.handleHTTPRequest(c)

// 再扔回 pool 中
engine.pool.Put(c)

案例2:fmt 中的 printer pool

printer 也符合長生命周期的特點,同時也會可能會在多 goroutine 中使用,所以也適合使用 pool 來維護。

printer 與 它的臨時對象池

// pp 用來維護 printer 的狀態
// 它通過 sync.Pool 來重用,避免申請內存
type pp struct {
 //... 字段已省略
}

var ppFree = sync.Pool{
 New: func() interface{} { return new(pp) },
}

獲取與釋放:

func newPrinter() *pp {
 p := ppFree.Get().(*pp)
 p.panicking = false
 p.erroring = false
 p.fmt.init(p.buf)
 return p
}

func (p *pp) free() {
 p.buf = p.buf[:0]
 p.arg = nil
 p.value = reflect.Value{}
 ppFree.Put(p)
}

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • Go語言中使用 buffered channel 實現線程安全的 pool
  • Go語言學習技巧之如何合理使用Pool

標簽:德宏 東營 保定 曲靖 吐魯番 許昌 貴州 常州

巨人網絡通訊聲明:本文標題《7分鐘讀懂Go的臨時對象池pool以及其應用場景》,本文關鍵詞  7分鐘,讀懂,的,臨時,對象,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《7分鐘讀懂Go的臨時對象池pool以及其應用場景》相關的同類信息!
  • 本頁收集關于7分鐘讀懂Go的臨時對象池pool以及其應用場景的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    欧美一区二区精品在线| 日韩精品一区二| 欧美亚洲综合色| 国产精品青草久久| 国产美女视频一区| 久久伊99综合婷婷久久伊| 久久精品国产99国产| 91麻豆精品国产91久久久资源速度| 亚洲成年人网站在线观看| 欧美美女一区二区三区| 久久电影网站中文字幕 | 欧美美女直播网站| 亚洲国产一二三| 欧美日韩国产高清一区二区三区 | 99视频在线观看一区三区| 国产精品美女久久久久高潮| 成人黄色av网站在线| 一区二区三区四区精品在线视频| www.亚洲国产| 亚洲成av人综合在线观看| 成人ar影院免费观看视频| 久久久91精品国产一区二区三区| 国产成人av在线影院| 亚洲激情网站免费观看| 欧美一级一级性生活免费录像| 国产酒店精品激情| 亚洲欧美日韩小说| 精品国产青草久久久久福利| 国产麻豆精品在线| 亚洲色图一区二区| 日韩视频在线观看一区二区| 波多野结衣91| 久久av中文字幕片| 依依成人综合视频| 久久久一区二区| 欧美日韩国产乱码电影| 日日夜夜精品视频免费| 亚洲欧美自拍偷拍| 精品国产乱码91久久久久久网站| 91在线云播放| 国产自产高清不卡| 美女尤物国产一区| 亚洲久本草在线中文字幕| 精品福利av导航| 91精品久久久久久蜜臀| 欧美唯美清纯偷拍| 99re热视频精品| 国产剧情在线观看一区二区| 美女一区二区视频| 午夜成人免费视频| 亚洲一区二区在线播放相泽| 2022国产精品视频| 欧美成人精品高清在线播放 | 欧美日韩一本到| 国产99一区视频免费| 国产中文字幕精品| 免费的成人av| 免费观看30秒视频久久| 亚洲精品中文在线观看| 国产精品入口麻豆原神| 国产精品美女久久久久久久久久久| 欧美在线看片a免费观看| 国产精一区二区三区| 日韩国产欧美在线观看| 一区二区三区在线免费观看| 国产精品每日更新在线播放网址| 久久综合久久99| 精品国产乱码久久久久久1区2区| 欧美日韩一区二区三区在线| 成人免费va视频| 成人一区二区三区视频 | 国产精品网曝门| 精品久久人人做人人爰| 亚洲精品一线二线三线| 欧美sm极限捆绑bd| 国产午夜三级一区二区三| 国产欧美一区二区三区在线看蜜臀 | 波多野结衣中文字幕一区| 懂色av一区二区三区免费看| 欧美在线视频全部完| 国产日韩精品一区| 蜜桃视频在线观看一区二区| 欧美综合亚洲图片综合区| 精品国产区一区| 国产成人在线网站| 中文字幕va一区二区三区| 国产精品一区二区男女羞羞无遮挡| 日韩免费观看2025年上映的电影| 精品综合免费视频观看| 亚洲精品一区二区三区香蕉| 成人短视频下载| 亚洲视频一二三区| 亚洲日本乱码在线观看| 午夜久久福利影院| 午夜国产不卡在线观看视频| 成人激情文学综合网| 日韩电影一区二区三区四区| 国产精品一二三区在线| 日韩视频在线你懂得| 久久综合久久综合亚洲| 国产精品全国免费观看高清 | 日本不卡视频在线| 国产一区二区三区免费在线观看| 成人午夜视频网站| 91丨九色丨尤物| 国产精品久久久久久一区二区三区 | 久久久久久久久久久电影| 国产精品免费视频网站| 亚洲国产一区二区视频| 久久久国产精华| 亚洲精品久久久蜜桃| 精品一区精品二区高清| 91无套直看片红桃| 91精品国产综合久久精品app| 久久久久久久电影| 亚洲福利一区二区| 成人美女视频在线观看| 欧美三级乱人伦电影| 亚洲欧洲日韩在线| 国产一区二区0| 欧美在线视频不卡| 1区2区3区国产精品| 国产精品18久久久久久久久| 精品少妇一区二区三区免费观看| 亚洲成av人片一区二区三区| www.欧美.com| 一区二区三区高清| 国产一区二区调教| 欧美剧情片在线观看| 亚洲综合色在线| 色综合天天综合网国产成人综合天| 久久久高清一区二区三区| 美国十次了思思久久精品导航| av男人天堂一区| 欧美电影精品一区二区| 午夜精品视频在线观看| 欧美性生活久久| 香蕉久久一区二区不卡无毒影院| 在线一区二区观看| 国产精品久久久久毛片软件| 成人毛片老司机大片| 欧美激情一区二区三区| 亚洲黄色小视频| 99re6这里只有精品视频在线观看| 精品亚洲欧美一区| 欧美三区在线观看| 三级精品在线观看| 欧美一区二区三区在线| 麻豆精品视频在线观看| 欧美精品一区二区久久婷婷| 国产一区二区调教| 中文字幕一区二区三区不卡在线 | 日本一区二区三区久久久久久久久不| 久久国产精品99精品国产| 日韩一级黄色片| 国产不卡在线一区| 久久免费视频一区| 99久久综合国产精品| 一区二区高清视频在线观看| 欧美精品乱码久久久久久按摩| 日韩电影在线观看一区| 91麻豆精品视频| 国产日韩欧美a| 日本精品免费观看高清观看| 日韩不卡一区二区三区| 国产欧美日韩中文久久| 成人免费高清视频| 亚洲高清不卡在线| 日韩欧美一区二区免费| 韩国成人福利片在线播放| 日韩美女视频19| 欧美mv日韩mv| 欧美午夜精品久久久久久超碰 | 久久亚洲一级片| 99视频精品在线| 青青草97国产精品免费观看无弹窗版 | 在线观看亚洲a| 午夜欧美在线一二页| 国产精品免费久久| 91精品国产综合久久久久久久| 成人国产电影网| 久久不见久久见免费视频1| 亚洲女子a中天字幕| 久久久影视传媒| 欧美精品在线一区二区| 成人动漫一区二区| 黑人巨大精品欧美一区| 午夜欧美视频在线观看| 亚洲欧美日本在线| 中文字幕欧美激情一区| 日韩午夜激情电影| 制服丝袜激情欧洲亚洲| 在线亚洲精品福利网址导航| 成人黄色一级视频| 国产精品性做久久久久久| 美女看a上一区| 日本成人在线不卡视频| 亚洲va欧美va国产va天堂影院| 亚洲素人一区二区| 欧美激情在线看|