資源受限的場景。例如,不需要可擴展性的環境(CPU、記憶體等實體資源有限),CPU效能不夠強勁,記憶體比較緊張,垃圾收集,記憶體抖動會造成比較大的影響,需要提高記憶體管理效率, 響應性比吞吐量更為重要。
在記憶體中數量受限的物件。
建立成本高的物件。
大量的存活期短且初始化成本低的物件池化,以降低記憶體分配和再分配成本,避免記憶體碎片。
Python 的這樣的動態語言,GC 是依靠引用技術來保證物件不會過早的回收,某些場景下可能出現雖然創建了但是沒人使用的空閒期,導致物件被回收了。可以委託給物件池來保管。
Pond 是一個Python 中高效率的通用物件池,具有效能好、記憶體佔用小、命中率高的特點。基於近似統計的根據頻率自動回收的能力,能夠自動調整每個物件池的空閒物件數量。
因為目前 Python 目前沒有比較好的、測試使用案例完整、程式碼註解完整、文件完善的物件池化函式庫,同時目前的主流物件庫也沒有比較智慧的自動回收機制。
Pond 可能是 Python 中第一個社群公開的測試案例完整,覆蓋率 90% 以上、程式碼註解完備、文件完善的物件池化函式庫。
Pond 靈感來自 Apache Commons Pool、Netty Recycler、HikariCP、Caffeine,集合了多家的優點。
其次 Pond 透過使用近似計數的方式以極小的記憶體空間統計每個物件池的使用頻率,並且自動回收。
流量較隨機平均的情況下,預設策略和權重可以降低 48.85% 記憶體佔用,借取命中率 100%。
流量較為符合 2/8 定律的情況下,預設策略和權重可以降低 45.7% 記憶體佔用, 借取命中率 100%。
Pond 主要由 FactoryDict、Counter、PooledObjectTree 三部分以及一個單獨的回收執行緒構成。
使用 Pond 需要實作物件工廠 PooledObjectFactory,PooledObjectFactory 提供物件的建立、初始化、銷毀、驗證等操作,由 Pond 呼叫。
所以為了讓物件池支援存放完全不同的對象,Pond 使用了一個字典來記錄每個工廠類別的名稱和自己實現的工廠類別的實例化物件。
每個 PooledObjectFactory 應該具備建立物件、銷毀物件、驗證物件是否還可用、重置物件四個功能。
比較特別的是Pond 支援自動重置對象,因為某些場景下可能會存在對像中要先賦值進行傳遞,傳遞完又被回收的情況,為了避免污染建議這種場景下無比實現這個功能。
Counter 中儲存了一個近似計數器。
PooleedObjectTree 是個字典,每個 key 對應一個先進先出的佇列,這些佇列都是執行緒安全的。
每個佇列中保存著多個 PooleedObject。 PooledObejct 保存了建立時間、最後借出的時間以及實際需要的物件。
Pond 的借用和回收都是線程安全的。 Python 的 queue 模組提供了一個適用於多執行緒程式設計的先進先出(FIFO)資料結構。它可以用來安全地在生產者和消費者線程之間傳遞訊息或其他資料。
鎖定是呼叫者來處理的,所有多個執行緒能夠安全且容易的使用相同的 Queue 實例工作。而 Pond 的借用和回收都是在操作 queue,所以基本上可以認為是線程安全的。
在使用Pond 借出一個物件時,會先檢查想要藉用的物件的種類是否已經在PooledObjectTree 存在,如果存在會檢查這個物件的物件池是否為空,如果為空會建立一個新的。
如果物件池中有多餘的對象,會利用 queue 彈出一個物件並驗證這個物件是否可用。如果不可用會自動呼叫所屬的 Factory 清理銷毀該對象,同時清理它在 Python 中的 GC 計數,讓它更快被 GC 回收,不斷拿取下一個直至有可用的。
如果這個物件可用,則會直接傳回。當然無論是從對像池中取出對象還是新創建了一個對象,都會利用 Counter 增加一個計數。
回收一個物件時會判斷目標物件池存不存在,如果存在會檢查物件池是否已經滿了,滿了的話會自動銷毀要歸還的這個物件。
然後會檢查這個物件是否已經被借出太長時間,如果超過了配置的最長時間同樣會被清理掉。
自動回收時每隔一段時間,預設是 300 s,就會執行一次。自動清理不經常使用的物件池中的物件。
你可以先安裝 Pond 的函式庫並且在你的專案中引用。
pip install pondpond
from pond import Pond, PooledObjectFactory, PooledObject
首先你需要聲明一個你想要放入的類型的物件的工廠類,例如下面的例子我們希望池化的物件是Dog,所以我們先聲明一個PooledDogFactory 類,並且實作PooledObjectFactory。
class Dog: name: str validate_result:bool = True class PooledDogFactory(PooledObjectFactory): def creatInstantce(self) -> PooledObject: dog = Dog() dog.name = "puppy" return PooledObject(dog) def destroy(self, pooled_object: PooledObject): del pooled_object def reset(self, pooled_object: PooledObject) -> PooledObject: pooled_object.keeped_object.name = "puppy" return pooled_object def validate(self, pooled_object: PooledObject) -> bool: return pooled_object.keeped_object.validate_result
接著你需要建立Pond 的物件:
pond = Pond(borrowed_timeout=2, time_between_eviction_runs=-1, thread_daemon=True, eviction_weight=0.8)
Pond 可以傳遞一些參數進去,分別代表:
borrowed_timeout :單位為秒,借出對象的最長期限,超過期限的物件歸還時會自動銷毀不會放入物件池。
time_between_eviction_runs :單位為秒,自動回收的間隔時間。
thread_daemon :守護線程,如果為 True,自動回收的線程會隨著主線程關閉而關閉。
eviction_weight :自動回收時權重,會將這個權重與最大使用頻次想乘,使用頻次小於這個值的物件池中的物件都會進入清理步驟。
實例化工廠類別:
factory = PooledDogFactory(pooled_maxsize=10, least_one=False)
所有繼承了 PooledObjectFactory 都會自帶建構函數,可以傳遞 pooled_maxsize 和 least_one 兩個參數。
pooled_maxsize:這個工廠類別產生的物件的物件池的最大能放置的數量。
least_one:如果為 True,在進入自動清理時,這個工廠類別產生的物件的物件池會至少保留一個物件。
向Pond 註冊這個工廠對象,預設會使用factory 的類別名稱作為PooledObjectTree 的key :
pond.register(factory)
當然你也可以自訂它的名字,名字會作為PooledObjectTree 的key:
pond.register(factory, name="PuppyFactory")
註冊成功後,Pond 會自動根據factory 中設定的pooled_maxsize 自動開始建立物件直到填滿這個物件池。
借用和歸還物件:
pooled_object: PooledObject = pond.borrow(factory) dog: Dog = pooled_object.use() pond.recycle(pooled_object, factory)
當然你可以用名字來進行借用和歸還:
pooled_object: PooledObject = pond.borrow(name="PuppyFactory") dog: Dog = pooled_object.use() pond.recycle(pooled_object, name="PuppyFactory")
完全清理一個物件池:
pond.clear(factory)
透過名字清理一個物件池:
pond.clear(name="PuppyFactory")
正常情況下,你只需要使用上面的這些方法,生成物件和回收物件都是全自動的。
以上是高效率的Python通用物件池化函式庫怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!