前言
物件池是一種設計模式,一個物件池包含一組已經初始化過且可以使用的物件,而可以在有需求時創建和銷毀物件,池的物件可以從池中取得物件,對其進行操作處理,并在不需要時歸還給池子而非直接銷毀他,他是一種特殊的工廠物件,
若初始化、實體化的代價高,且有需求需要經常實體化,但每次實體化的數量較小的情況下,使用物件池可以過得顯著的性能提升,從池子中取得物件的時間是可測的,但新建一個實際所需要的時間是不確定的,
物件池的優勢
說到池我們就會聯想到很多的概念,如執行緒池、資料庫連接池、記憶體池等等在多執行緒設計中可以通過池化機制來進行物件的復用從而提高性能,池的核心優勢是 物件復用,這樣就免去了物件創建的開銷以及回收產生的內容開銷,尤其創建物件這是一個很耗時的事情比如IO操作.
拿我們最常見的執行緒池為例,執行緒這個物件是可以復用的,程式要執行的任務,這些任務可以交給復用的執行緒來處理,而執行緒池創建恰恰又是一個比較耗時的操作,我們通過執行緒物件的池化技術達到復用執行緒的目的,

ConcurrentBag實作物件池
池化中需要注意的是多執行緒中保證執行緒安全,.NET Framework 4 引入了 System.Collections.Concurrent 命名空間,其中包含多個執行緒安全且可縮放的集合類, 多個執行緒可以安全高效地從這些集合添加或洗掉項,而無需在用戶代碼中進行其他同步, 撰寫新代碼時,只要將多個執行緒同時寫入到集合時,就使用并發集合類,
ObjectPool
- Get方法用于從物件池獲取到可用物件,如果物件不可用則創建物件并回傳出來
- Return方法用戶將物件回傳到物件池
public class ObjectPool<T>
{
private ConcurrentBag<T> _object;
private Func<T> _objectGenerator;
public ObjectPool(Func<T> objectGenerator) {
_object = new ConcurrentBag<T>();
_objectGenerator = objectGenerator;
}
/// <summary>
/// 取出
/// </summary>
/// <returns></returns>
public T CheckOut() {
T item;
if (_object.TryTake(out item)) return item;
return _objectGenerator();
}
/// <summary>
/// 歸還
/// </summary>
/// <param name="obj"></param>
public void CheckIn(T obj) {
_object.Add(obj);
}
}
測驗
class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
// Create an opportunity for the user to cancel.
Task.Run(() =>
{
if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
cts.Cancel();
});
ObjectPool<MyClass> pool = new ObjectPool<MyClass>(() => new MyClass());
// Create a high demand for MyClass objects.
Parallel.For(0, 1000000, (i, loopState) =>
{
MyClass mc = pool.CheckOut();
Console.CursorLeft = 0;
// This is the bottleneck in our application. All threads in this loop
// must serialize their access to the static Console class.
Console.WriteLine("{0:####.####}", mc.GetValue(i));
pool.CheckIn(mc);
if (cts.Token.IsCancellationRequested)
loopState.Stop();
});
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
cts.Dispose();
}
class MyClass
{
public int[] Nums { get; set; }
public double GetValue(long i)
{
return Math.Sqrt(Nums[i]);
}
public MyClass()
{
Nums = new int[1000000];
Random rand = new Random();
for (int i = 0; i < Nums.Length; i++)
Nums[i] = rand.Next();
}
}
}
這是一個簡單的物件池實作,在實際的場景中還需要考慮最小值,最大值,例外處理等等
總結
在創建資源時會消耗一定的系統資源,尤其在及其復雜的結構中效果相對來說是挺明顯的,再加上頻繁的創建,實體化消耗的資源是很昂貴的.物件池對這些提成是相當有幫助的.
并非任何情況下都需要使用物件池,在復用生成某種物件的操作成為影響性能因素的時候,才適合采用物件池,如果物件池提成性能提高并不重要的話,還是建議不采用物件池,保持代碼簡單.
參考
https://zh.m.wikipedia.org/zh-cn/%E5%AF%B9%E8%B1%A1%E6%B1%A0%E6%A8%A1%E5%BC%8F
https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/87869.html
標籤:.NET Core
