基于.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);
                }
            }
        }
    }

 

posted @ 2013-03-13 15:22  爱淋雨的男孩  阅读(1264)  评论(1编辑  收藏  举报