《编程篇》已经涉及到了对象池模型的大部分核心接口和类型。对象池模型其实是很简单的,不过其中有一些为了提升性能而刻意为之的实现细节倒是值得我们关注。总的来说,对象池模型由三个核心对象构成,它们分别是表示对象池的ObjectPool
一、 IPooledObjectPolicy
我们在《编程篇》已经说过,表示池化对象策略的IPooledObjectPolicy
public interface IPooledObjectPolicy{ T Create(); bool Return(T obj); } public abstract class PooledObjectPolicy : IPooledObjectPolicy { protected PooledObjectPolicy(){} public abstract T Create(); public abstract bool Return(T obj); }
我们默认使用的是如下这个DefaultPooledObjectPolicy
public class DefaultPooledObjectPolicy: PooledObjectPolicy where T: class, new() { public override T Create() => Activator.CreateInstance (); public override bool Return(T obj) => true; }
二、ObjectPool
对象池通过ObjectPool
public abstract class ObjectPoolwhere T: class { protected ObjectPool(){} public abstract T Get(); public abstract void Return(T obj); }
DefaultObjectPool
我们默认使用的对象池体现为一个DefaultObjectPool
如下面的代码片段所示,DefaultObjectPool
public class DefaultObjectPool: ObjectPool where T : class { private protected T _firstItem; private protected readonly ObjectWrapper[] _items; … private protected struct ObjectWrapper { public T Element; } }
DefaultObjectPool
public class DefaultObjectPool: ObjectPool where T : class { private protected T _firstItem; private protected readonly ObjectWrapper[] _items; private protected readonly IPooledObjectPolicy _policy; private protected readonly bool _isDefaultPolicy; private protected readonly PooledObjectPolicy _fastPolicy; public DefaultObjectPool(IPooledObjectPolicy policy) : this(policy, Environment.ProcessorCount * 2) {} public DefaultObjectPool(IPooledObjectPolicy policy, int maximumRetained) { _policy = policy ; _fastPolicy = policy as PooledObjectPolicy ; _isDefaultPolicy = IsDefaultPolicy(); _items = new ObjectWrapper[maximumRetained - 1]; bool IsDefaultPolicy() { var type = policy.GetType(); return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(DefaultPooledObjectPolicy<>); } } [MethodImpl(MethodImplOptions.NoInlining)] private T Create() => _fastPolicy?.Create() ?? _policy.Create(); }
从第二个构造函数的定义可以看出,指定的IPooledObjectPolicy
如下所示的是重写的Get和Return方法的定义。用于提供池化对象的Get方法很简单,它会采用原子操作使用Null将_firstItem字段表示的对象“替换”下来,如果该字段不为Null,那么将其作为返回的对象,反之它会遍历数组的每个ObjectWrapper对象,并使用Null将其封装的对象“替换”下来,第一个成功替换下来的对象将作为返回值。如果所有ObjectWrapper对象封装的对象都为Null,意味着所有对象都被“借出”或者尚未创建,此时返回创建的新对象了。
public class DefaultObjectPool: ObjectPool where T : class { public override T Get() { var item = _firstItem; if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item) { var items = _items; for (var i = 0; i < items.Length; i++) { item = items[i].Element; if (item != null && Interlocked.CompareExchange( ref items[i].Element, null, item) == item) { return item; } } item = Create(); } return item; } public override void Return(T obj) { if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj))) { if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null) { var items = _items; for (var i = 0; i < items.Length && Interlocked.CompareExchange( ref items[i].Element, obj, null) != null; ++i) {} } } } … }
将对象释放会对象池的Return方法也很好理解。首先它需要判断指定的对象能否释放会对象池中,如果使用的是默认的池化对象策略,答案是肯定的,否则只能通过调用IPooledObjectPolicy
在确定指定的对象可以释放回对象之后,如果_firstItem字段为Null,Return方法会采用原子操作使用指定的对象将其“替换”下来。如果该字段不为Null或者原子替换失败,该方法会便利数组的每个ObjectWrapper对象,并采用原子操作将它们封装的空引用替换成指定的对象。整个方法会在某个原子替换操作成功或者整个便利过程结束之后返回。
DefaultObjectPool
DisposableObjectPool
通过前面的示例演示我们知道,当池化对象类型实现了IDisposable接口的情况下,如果某个对象在回归对象池的时候,对象池已满,该对象将被丢弃。与此同时,被丢弃对象的Dispose方法将立即被调用。但是这种现象并没有在DefaultObjectPool
internal sealed class DisposableObjectPool: DefaultObjectPool , IDisposable where T : class { private volatile bool _isDisposed; public DisposableObjectPool(IPooledObjectPolicy policy) : base(policy) {} public DisposableObjectPool(IPooledObjectPolicy policy, int maximumRetained) : base(policy, maximumRetained) {} public override T Get() { if (_isDisposed) { throw new ObjectDisposedException(GetType().Name); } return base.Get(); } public override void Return(T obj) { if (_isDisposed || !ReturnCore(obj)) { DisposeItem(obj); } } private bool ReturnCore(T obj) { bool returnedToPool = false; if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj))) { if (_firstItem == null && Interlocked.CompareExchange(ref _firstItem, obj, null) == null) { returnedToPool = true; } else { var items = _items; for (var i = 0; i < items.Length && !(returnedTooPool = Interlocked.CompareExchange(ref items[i].Element, obj, null) == null); i++) {} } } return returnedTooPool; } public void Dispose() { _isDisposed = true; DisposeItem(_firstItem); _firstItem = null; ObjectWrapper[] items = _items; for (var i = 0; i < items.Length; i++) { DisposeItem(items[i].Element); items[i].Element = null; } } private void DisposeItem(T item) { if (item is IDisposable disposable) { disposable.Dispose(); } } }
从上面代码片段可以看出,DisposableObjectPool
三、ObjectPoolProvider
表示对象池的ObjectPool
public abstract class ObjectPoolProvider { public ObjectPoolCreate () where T : class, new() => Create (new DefaultPooledObjectPolicy ()); public abstract ObjectPool Create (IPooledObjectPolicy policy) where T : class; }
在前面的示例演示中,我们使用的是如下这个DefaultObjectPoolProvider类型。如代码片段所示,DefaultObjectPoolProvider派生于抽象类ObjectPoolProvider,在重写的Create
public class DefaultObjectPoolProvider : ObjectPoolProvider { public int MaximumRetained { get; set; } = Environment.ProcessorCount * 2; public override ObjectPoolCreate (IPooledObjectPolicy policy) => typeof(IDisposable).IsAssignableFrom(typeof(T)) ? new DisposableObjectPool (policy, MaximumRetained) : new DefaultObjectPool (policy, MaximumRetained); }
DefaultObjectPoolProvider类型定义了一个标识对象池大小的MaximumRetained属性,采用处理器数量的两倍作为默认容量也体现在这里。这个属性并非只读,所以我们可以利用它根据具体需求调整提供对象池的大小。在ASP.NET应用中,我们基本上都会采用依赖注入的方式利用注入的ObjectPoolProvider对象来创建针对具体类型的对象池。我们在《编程篇》还演示了另一种创建对象池的方式,那就是直接调用ObjectPool类型的静态Create
public static class ObjectPool { public static ObjectPoolCreate (IPooledObjectPolicy policy) where T: class, new() => new DefaultObjectPoolProvider().Create (policy ?? new DefaultPooledObjectPolicy ()); }
到目前为止,我们已经将整个对象池的设计模型进行了完整的介绍。总得来说,这是一个简单、高效并且具有可扩展性的对象池框架,该模型涉及的几个核心接口和类型体现在如下图所示的UML中。
.NET Core对象池的应用:编程篇
.NET Core对象池的应用:扩展篇
到此这篇关于.NET Core对象池的应用:设计篇的文章就介绍到这了,更多相关.NET Core对象池的应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!