在C#中实现简单的对象池

当我们频繁创建删除大量对象的时候,对象的创建删除所造成的开销就不容小觑了。为了提高性能,我们往往需要实现一个对象池作为Cache:使用对象时,它从池中提取。用完对象时,它放回池中。从而减少创建对象的开销。

由于.net BCL库中并没有对象池的标准实现,因此需要我们自己去实现。好在实现功能简单的对象池并不麻烦,一般几十行代码就能实现。需要注意的一点是,对象池大多是需要支持多线程访问的,因此需要考虑线程安全问题。

在.Net 4.0后,BCL在System.Collections.Concurrent名字空间下引入了一系列线程安全的对象,微软甚至在MSDN上给了一个通过实现对象池的简单示例:How to: Create an Object Pool by Using a ConcurrentBag.

这个例子本身没有什么问题,但如果放在实际生产中就觉得有点简单过头了,一般还需要加上容量限制和重用时进行reset操作。这里我就稍微将其改了下: 

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

你可能感兴趣的:(对象池)