基于.NET 并行库写的对象池
ObjectPoolBase类,大家不用去于解TObjectPool, TObjectPoolDomain, TObjectDomain三个泛型参数,改成一个TObject也可以使用
其构造中的四个参数分别代表:
minSize:池中最少个数
maxSize:池中最大个数
growSize:增长/回收个数
maintenanceMilliseconds:维护间隔
运行机制:
在BorrowObject时,如果可以在FREES中取得对象则返回,如果获取失败,则当池中对象个数小于最大个数时,创建对象,否则等待对象返还并重试。
当使用完对象时可通过ReturnObject返还对象
对象池在指定的maintenanceMilliseconds的间隔内会维护池子的大小
可重载对象池的OnCreateObject创建对象,OnDestroyObject销毁对象,OnActiveObject激活对象和OnDeactivate使对象进入休眠
可使用USING语句在跳出代码块是自动返还对象
using(var po = ObjectPool.GetPoolPoolObject())
{
po.Object.xxx();
....
}
具体代码如下:
public abstract class ObjectPoolBase<TObjectPool, TObjectPoolDomain, TObject, TObjectDomain> where TObjectPool : ObjectPoolBase<TObjectPool, TObjectPoolDomain, TObject, TObjectDomain> where TObject : class { static ObjectPoolBase() { Instance = ContainerManager.Resolve<TObjectPool, TObjectPoolDomain>(); ObjectPoolManager.Instance.RegisterObjectPool<TObjectPool, TObjectPoolDomain, TObject, TObjectDomain>(Instance); } public static TObjectPool Instance { get; private set; } public static IPoolObject<TObject> GetPoolObject() { return new InternalPoolObject(); } private ConcurrentBag<TObject> frees; private ConcurrentDictionary<TObject, byte> borrowed; private long count; private int minSize; private int growSize; private int maxSize; private long maintenanceMilliseconds; private Timer maintenanceTimer; private AutoResetEvent are; private volatile bool exit; protected ObjectPoolBase(int minSize, int growSize, int maintenanceMillseconds) : this(minSize, int.MaxValue, growSize, maintenanceMillseconds) { } public ObjectPoolBase(int minSize, int maxSize, int growSize, int maintenanceMillseconds) { CheckUtility.ArgumentPositiveNumber(minSize, "minSize"); CheckUtility.ArgumentPositiveNumber(growSize, "growSize"); CheckUtility.ArgumentPositiveNumber(maintenanceMillseconds, "maintenanceMillseconds"); CheckUtility.ArgumentGreaterThanArgument(minSize, "minSize", maxSize, "maxSize"); this.minSize = minSize; this.growSize = growSize; this.maxSize = maxSize; this.maintenanceMilliseconds = maintenanceMillseconds; this.frees = new ConcurrentBag<TObject>(); this.borrowed = new ConcurrentDictionary<TObject, byte>(); this.count = 0; this.are = new AutoResetEvent(false); this.exit = false; this.maintenanceTimer = new Timer(this.TaskMaintenance, null, this.maintenanceMilliseconds, Timeout.Infinite); } public void Shutdown() { if (this.exit) { return; } this.exit = true; this.are.WaitOne(); } private bool ShutdownIfExit() { if (this.exit) { this.are.Set(); } return this.exit; } private void WriteToLog(string messageFormat, params object[] args) { string message = CheckUtility.ArrayIsNullOrEmpty(args) ? messageFormat : string.Format(messageFormat, args); LoggingWriter.WriteFormat("[{0}] {1} {2}", this.PoolName, message, this); } private void TaskMaintenance(object state) { this.WriteToLog("Trigger Maintenance"); if (this.ShutdownIfExit()) { return; } Task.Factory.StartNew(() => { if (this.ShutdownIfExit()) { return; } this.WriteToLog("Begin Maintenance"); if (Interlocked.Read(ref this.count) <= this.maxSize) { lock (this) { if (Interlocked.Read(ref this.count) <= this.maxSize) { if (this.frees.Count > this.minSize) { this.MaintenanceDestroy(Math.Min(this.growSize, Math.Abs(this.frees.Count - this.minSize))); } else if (this.frees.Count < this.minSize) { this.MaintenanceCreate(Math.Min(this.growSize, Math.Abs(this.frees.Count - this.minSize))); } } } } this.WriteToLog("After Maintenance"); if (this.ShutdownIfExit()) { return; } this.maintenanceTimer.Change(this.maintenanceMilliseconds, Timeout.Infinite); }, TaskCreationOptions.LongRunning); } public TObject BorrowObject() { this.WriteToLog("Before Borrow"); TObject t; do { if (!this.frees.TryTake(out t)) { lock (this) { while (!this.frees.TryTake(out t)) { if (this.exit) { throw new ObjectDisposedException(this.GetType().FullName); } long count = Interlocked.Read(ref this.count); if (Interlocked.Read(ref this.count) >= this.maxSize) { Monitor.Wait(this, 10000); continue; } else { long growSize = Math.Min(this.growSize, Math.Abs(this.count + this.growSize - this.maxSize)); if (growSize <= 0) { Monitor.Wait(this, 10000); continue; } else { this.MaintenanceCreate(growSize); } } } } } } while (!this.ActiveObject(t)); this.borrowed.TryAdd(t, 0); this.OnBorrow(t); this.WriteToLog("AfterBorrow"); return t; } protected virtual void OnBorrow(TObject obj) { } public void ReturnObject(TObject obj) { "obj".NullArgument(obj); this.WriteToLog("Before Return"); byte b; if (!this.borrowed.TryRemove(obj, out b)) { throw new InvalidOperationException(SR.InvalidObjectForPool); } if (this.DeactiveObject(obj)) { this.frees.Add(obj); } else { Interlocked.Decrement(ref this.count); } this.WriteToLog("After Return"); } protected void MaintenanceCreate(long size) { this.WriteToLog("Before Maintenance Create size: {0}", size); Parallel.For(0, size, (i) => { if (this.exit) { return; } if (Interlocked.Read(ref this.count) < this.maxSize) { TObject t; if (this.CreateObject(out t)) { this.frees.Add(t); Interlocked.Increment(ref this.count); } } }); this.WriteToLog("After Maintenance Create"); } protected void MaintenanceDestroy(long size) { this.WriteToLog("Before Maintenance Destroy size: {0}", size); Parallel.For(0, size, (i) => { if (this.exit) { return; } TObject t; if (this.frees.TryTake(out t)) { this.DestroyObject(t); Interlocked.Decrement(ref this.count); } }); this.WriteToLog("After Maintenance Destroy"); } private bool CreateObject(out TObject t) { this.WriteToLog("Create Object"); t = default(TObject); try { t = this.OnCreateObject(); if (null == t) { throw new NullReferenceException(SR.CreatedNullObjectForPool); } this.WriteToLog("Object Created"); return true; } catch (Exception e) { LoggingWriter.WriteLog(e); return false; } } protected virtual TObject OnCreateObject() { return ContainerManager.Resolve<TObject, TObjectDomain>(); } private bool ActiveObject(TObject t) { this.WriteToLog("Active Object"); try { this.OnActiveObject(t); return true; } catch (Exception e) { LoggingWriter.WriteLog(e); this.DestroyObject(t); return false; } } protected virtual void OnActiveObject(TObject obj) { } private bool DeactiveObject(TObject t) { this.WriteToLog("Deactive Object"); try { this.OnDeactivateObject(t); return true; } catch (Exception e) { LoggingWriter.WriteLog(e); this.DestroyObject(t); return false; } } protected virtual void OnDeactivateObject(TObject obj) { } private void DestroyObject(TObject t) { this.WriteToLog("Destroy Object"); try { byte b; if (this.borrowed.TryRemove(t, out b)) { Interlocked.Decrement(ref this.count); this.OnDestroyObject(ref t); } } catch (Exception e) { LoggingWriter.WriteLog(e); } } protected virtual void OnDestroyObject(ref TObject obj) { IDisposable disposable = obj as IDisposable; if (null != disposable) { try { disposable.Dispose(); } catch (Exception e) { LoggingWriter.WriteLog(e); } } else { obj = null; } } public virtual string PoolName { get { return typeof(TObjectPool).Name; } } public override string ToString() { return string.Format("[Pool Info] count: {0}, frees {1}, borrowed {2}, minSize {3}, maxSize {4} growSize {5}", Interlocked.Read(ref this.count), this.frees.Count, this.borrowed.Count, this.minSize, this.maxSize, this.growSize); } private class InternalPoolObject : IPoolObject<TObject>, IDisposable { private TObject obj; public InternalPoolObject() { this.obj = null; } public TObject Object { get { if (null == this.obj) { this.obj = Instance.BorrowObject(); } return this.obj; } } public void Dispose() { if (null != this.obj) { Instance.ReturnObject(this.obj); } } } }