在C#中實現簡單的對象池


當我們頻繁創建刪除大量對象的時候,對象的創建刪除所造成的開銷就不容小覷了。為了提高性能,我們往往需要實現一個對象池作為Cache:使用對象時,它從池中提取。用完對象時,它放回池中。從而減少創建對象的開銷。

由於.net BCL庫中並沒有對象池的標准實現,因此需要我們自己去實現。好在實現功能簡單的對象池並不麻煩,一般幾十行代碼就能實現。需要注意的一點是,對象池大多是需要支持多線程訪問的,因此需要考慮線程安全問題。

在.Net 4.0后,BCL在System.Collections.Concurrent名字空間下引入了一系列線程安全的對象,微軟甚至在MSDN上給了一個通過實現對象池的簡單示例:How to: Create an Object Pool by Using a ConcurrentBag.

這個例子本身沒有什么問題,但如果放在實際生產中就覺得有點簡單過頭了,一般還需要加上容量限制和重用時進行reset操作。這里我就稍微將其改了下: 

 1 public class ObjectPool<T>
 2     {
 3         ConcurrentBag<T> buffer;
 4         Func<T> createFunc;
 5         Action<T> resetFunc;
 6 
 7         public ObjectPool(Func<T> createFunc, Action<T> resetFunc, int capacity)
 8         {
 9             Contract.Assume(createFunc != null);
10             Contract.Assume(capacity > 0);
11 
12             this.buffer = new ConcurrentBag<T>();
13             this.createFunc = createFunc;
14             this.resetFunc = resetFunc;
15 
16             this.Capacity = capacity;
17         }
18 
19         public int Capacity { get; private set; }
20         public int Count { get { return buffer.Count; } }
21 
22         /// <summary>
23         /// 申請對象
24         /// </summary>
25         public T GetObject()
26         {
27             var obj = default(T);
28 
29             if (!buffer.TryTake(out obj))
30                 return createFunc();
31             else
32                 return obj;
33         }
34 
35         /// <summary>
36         /// 釋放對象
37         /// </summary>
38         public void PutObject(T obj)
39         {
40             Contract.Assume(obj != null);
41 
42             if (Count >= Capacity)        //超過容量了,不再需要
43                 return;
44 
45             if (resetFunc != null)
46                 resetFunc(obj);
47 
48             buffer.Add(obj);
49         }
50     }
View Code

需要注意的是,我這里的實現並沒有完全確保Capacity的絕對性:當兩個線程同時往一個即將到達上限的對象池中放置對象時,可能都會成功。因為我覺得這個是沒有太大必要的,感興趣的朋友可以把它改下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM