真實世界的 Go 設計模式 - 對象池模式

對象池(object pool pattern)是一種設計模式。一個對象池包含一組已經初始化過且可以使用的對象,而可以在有需求時創建和銷燬對象。池的用戶可以從池子中取得對象,對其進行操作處理,並在不需要時歸還給池子而非直接銷燬它。這是一種特殊的工廠對象。

若初始化、實例化的代價高,且有需求需要經常實例化,但每次實例化的數量較少的情況下,使用對象池可以獲得顯著的效能提升。從池子中取得對象的時間是可預測的,但新建一個實例所需的時間是不確定。

另外,利用對象池,我們可以重用對象,減少對象的分配,對於垃圾回收的編程語言,也是一種提高性能的手段。

sync.Pool 是 Go 標準庫 sync 包中的一個非常有用的結構, 它可以用來管理和重用臨時對象, 以減少對象頻繁分配和回收的開銷。

sync.Pool 的主要特點包括:

通過重用對象, 可以減少內存分配和垃圾回收的開銷, 特別適合用於管理許多臨時對象的場景, 如處理大量併發請求時的緩衝、連接等。

比如 net/rpc 包就使用了鏈表來管理常用的 Response、Request 等對象的重用。

Go 標準庫 database/sql 包實現了一個連接池, 可以重用數據庫連接。使用 DB.Conn() 獲取連接對象, 操作完成後調用 conn.Close() 將其放回池中。該連接池默認最大空閒連接數 2, 可以通過 SetMaxIdleConns 進行調整。

fatih/pool[1] 也是一個常用的網絡連接池。

還有一類是 goroutine pool, 也又叫做 worker pool 的,這類的庫就很多的,而且還有人源源不斷的造輪子。比如常用的比如:

因爲使用 channel + goroutine 很容易實現 goroutine pool, 所以也有很多關注度不高的輪子,都是作者針對自己的需求定製和改造的。使用也很方便。

Go 標準庫還有一個實驗性的包arena, 本來就在 Go 1.20 中就要推出的,但是在實現的過程中發現有問題,就一直沒有暴露出來。proposal: arena: new package providing memory arenas [6] 這個提案詳細介紹了內容。你也可以把它看成是一個內存池,從其中產生的對象不會被垃圾回收掉,能夠提升程序的性能。

參考資料

[1]

fatih/pool: https://github.com/fatih/pool

[2]

Jeffail/tunny: https://github.com/Jeffail/tunny

[3]

panjf2000/ants: https://github.com/panjf2000/ants

[4]

ivpusic/grpool: https://github.com/ivpusic/grpool

[5]

alitto/pond: https://github.com/alitto/pond

[6]

proposal: arena: new package providing memory arenas : https://github.com/golang/go/issues/51317

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/p5lv_yTUbxsNYDmZiIpGTw