在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的绝对性:当两个线程同时往一个即将到达上限的对象池中放置对象时,可能都会成功。因为我觉得这个是没有太大必要的,感兴趣的朋友可以把它改下。

原文地址:https://www.cnblogs.com/TianFang/p/3411399.html