網(wǎng)上關(guān)于sync.Pool的源碼分析的文章比較多,本文的重點(diǎn)不在于源碼分析,而在于簡單易懂的介紹一下sync.Pool的內(nèi)部實(shí)現(xiàn)方式,如果想要了解更多,可以看下參考中的文章
本文基于Go1.14
參考:https://www.cnblogs.com/qcrao-2018/p/12736031.html
先看下Pool的整體結(jié)構(gòu):
整個結(jié)構(gòu)實(shí)際上可以簡化為每一個PoolLocal實(shí)現(xiàn)了一個雙向列表,其中每個節(jié)點(diǎn)用數(shù)組的方式來實(shí)現(xiàn)了循環(huán)列表。
- 雙向鏈表是為了可不限長度的擴(kuò)展。
- 雙向鏈表中每個節(jié)點(diǎn)都保存一個數(shù)組來實(shí)現(xiàn)循環(huán)隊(duì)列,數(shù)組長度初始為8,每新增一個節(jié)點(diǎn),數(shù)組長度變?yōu)樵瓉淼?倍(直到最大限制),以此來動態(tài)的適應(yīng)對象的數(shù)量,并且不至于讓鏈表過長。
- private,PoolLocal數(shù)組是為了避免上鎖,以提升性能。
- pad涉及cpu緩存,參考:http://m.itdecent.cn/p/dc4b5562aad2
第二張圖很形象的說明了多個P之間的對象共享,如果P1/P2/P3內(nèi)部沒有可用對象了怎么辦?從P0的隊(duì)尾取對象,而P0自身是從對頭,從而避免了鎖競爭。
當(dāng)然還有很多細(xì)節(jié),比如維護(hù)所有Pool的AllPools和oldPools,比如victim和local,旨在垃圾回收和對象分配之間做一個平衡,防止對象池中對象一次性全部回收造成突發(fā)的大量新對象帶來內(nèi)存申請等等。這些細(xì)節(jié)可以看源碼慢慢去體會。

image.png

image.png
是不是看著比較暈,其實(shí)是內(nèi)部各種套娃,核心思想都是為了盡可能減少并發(fā)導(dǎo)致的資源競爭以及有效利用cpu緩存。