QFramework框架学习(二) ------ 对象池

QFramework 是一套 渐进式 的 快速开发 框架。目标是作为无框架经验的公司、独立开发者、以及 Unity3D 初学者们的 第一套框架。框架内部积累了多个项目的在各个技术方向的解决方案。学习成本低,接入成本低,重构成本低,二次开发成本低,文档内容丰富(提供使用方式以及原理、开发文档)。github:https://github.com/liangxiegame/QFramework


在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题:

  • 一是减少new时候寻址造成的消耗,该消耗的原因是内存碎片。
  • 二是减少Object.Instantiate时内部进行序列化和反序列化而造成的CPU消耗。
在此之前,首先你需要知道C# This扩展知识,已经给你总结好啦 : 

                        https://blog.csdn.net/dengshunhao/article/details/80944994

首先来看对象池的老祖宗,定义了一个分配函数以及回收函数

   public interface IPool<T>
    {
        T Allocate();

        bool Recycle(T obj);
    }

定义一个计算当前剩余可分配数量的接口ICountObserveAble,这个值其实就是后面栈元素的数量

   //当前栈的数量,pool继承于它
    public interface ICountObserveAble
    {
        int CurCount { get; }
    }
定义一个Pool,继承上面两个接口,并实现里面的方法
   using System.Collections.Generic;

    public abstract class Pool<T> : IPool<T>,ICountObserveAble
    {
        #region ICountObserverable
        //返回池的数量
        public int CurCount
        {
            get { return mCacheStack.Count; }
        }
        #endregion
        //抽象工厂
        protected IObjectFactory<T> mFactory;

        protected readonly Stack<T> mCacheStack = new Stack<T>(); //池容器

        //默认为12
        protected int mMaxCount = 12;
        //分配
        public virtual T Allocate()
        {
            return mCacheStack.Count == 0
                ? mFactory.Create()
                : mCacheStack.Pop();  //当栈还有元素时就pop,没有就重新创建
        }
        //回收
        public abstract bool Recycle(T obj);
    }

还有定义一个创建方法:

   //抽象工厂
    public interface IObjectFactory<T>
    {
        T Create();
    }

①适合用于项目开发SimpleObjectPool :

框架定义了一个对action的扩展方法

   public static bool InvokeGracefully<T>(this Action<T> selfAction, T t)
        {
            if (null != selfAction)
            {
                selfAction(t);
                return true;
            }
            return false;
        }

完整实现:

  public class SimpleObjectPool<T> : Pool<T>
    {
        readonly Action<T> mResetMethod; //回收方法,由初始化时决定

        public SimpleObjectPool(Func<T> factoryMethod, Action<T> resetMethod = null,int initCount = 0)
        {
            mFactory = new CustomObjectFactory<T>(factoryMethod);  //factoryMethod是传入对象的初始化方法
            mResetMethod = resetMethod;  //回收方法
            //初始化
            for (int i = 0; i < initCount; i++)
            {
                mCacheStack.Push(mFactory.Create()); //mFactory.Create()调用的就是factoryMethod方法
            }
        }

        public override bool Recycle(T obj)
        {
            mResetMethod.InvokeGracefully(obj); //调用该对象的回收方法
            mCacheStack.Push(obj); //压入栈
            return true;
        }
    }

示例程序:

       public class SimpleObjectPoolExample : MonoBehaviour
	{
		/// <summary>
		/// 
		/// </summary>
		public class Fish 
		{
			
		}
		
		private void Start()
		{
			var fishPool = new SimpleObjectPool<Fish>(() => new Fish(), null, 100);

			Log.I("fishPool.CurCount:{0}", fishPool.CurCount);

			var fishOne = fishPool.Allocate();
			
			Log.I("fishPool.CurCount:{0}", fishPool.CurCount);

			fishPool.Recycle(fishOne);
			
			Log.I("fishPool.CurCount:{0}", fishPool.CurCount);

			for (int i = 0; i < 10; i++)
			{
				fishPool.Allocate();
			}
			
			Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
		}
	}

②适合用于库级开发,更多限制,要求开发者一开始就想好,更安全的SafeObjectPool :

定义以下两个接口,需要使用安全对象池的需要继承这两个接口:

  //将回收操作开放给用户,因为用户可能需要在回收对象之前进行一些操作,并且实现的时候需要调用该对象池对象回收对象
    public interface IPoolType
    {
        void Recycle2Cache();
    }

    //给泛型加上约束 保证T是继承IPoolable的,同时将回收操作开放
    public interface IPoolable
    {
        void OnRecycled(); //对象的回收操作
        bool IsRecycled { get; set; }  //表示对象是否被回收过
    }

SafeObjectPool的完整实现(可以无限取,但是缓存池中就存最大值数量的元素):

  //对象池
    public class SafeObjectPool<T> : Pool<T>, ISingleton where T : IPoolable, new()
    {
        #region Singleton
        void ISingleton.OnSingletonInit() {}

        protected SafeObjectPool()
        {
            mFactory = new DefaultObjectFactory<T>();
        }

        public static SafeObjectPool<T> Instance
        {
            get { return SingletonProperty<SafeObjectPool<T>>.Instance; }
        }
        //释放,即置空
        public void Dispose()
        {
            SingletonProperty<SafeObjectPool<T>>.Dispose();
        }
        #endregion

        //初始化 maxCount:最大数量 initCount:初始化数量
        public void Init(int maxCount, int initCount)
        {
            MaxCacheCount = maxCount;
            
            if (maxCount > 0)
            {
                initCount = Math.Min(maxCount, initCount);
            }
            //当前对象池内的对象数量小于要初始化的数量,开始初始化
            if (CurCount < initCount)
            {
                for (int i = CurCount; i < initCount; ++i)
                {
                    //初始化化之后的,并让其处于回收状态
                    Recycle(new T());
                }
            }
        }
        
        public int MaxCacheCount
        {
            get { return mMaxCount; }
            set
            {
                mMaxCount = value;

                if (mCacheStack != null)
                {
                    if (mMaxCount > 0)
                    {
                        if (mMaxCount < mCacheStack.Count)
                        {
                            int removeCount = mMaxCount - mCacheStack.Count;
                            while (removeCount > 0)
                            {
                                mCacheStack.Pop();
                                --removeCount;
                            }
                        }
                    }
                }
            }
        }
        //分配一个对象
        public override T Allocate()
        {
            var result = base.Allocate(); //如果栈的数量>0,则栈顶元素pop
            result.IsRecycled = false; //分配的时候置位false
            return result;
        }

        //回收一个对象
        public override bool Recycle(T t)
        {
            if (t == null || t.IsRecycled)  //判断是否已经回收
            {
                return false;
            }
            //当超过设置的最大限制时不push入栈中,只是执行回收函数,之后会自动销毁
            if (mMaxCount > 0)
            {
                if (mCacheStack.Count >= mMaxCount)
                {
                    t.OnRecycled();
                    return false;
                }
            }

            t.IsRecycled = true;
            t.OnRecycled();       //对象的回收操作
            mCacheStack.Push(t);

            return true;
        }
    }

只看这些还是有点懵的,看下作者提供的示例就很清晰了

public class SafeObjectPoolExample : MonoBehaviour
	{
		class Msg : IPoolable,IPoolType
		{
			#region IPoolAble 实现

			public void OnRecycled()
			{
				Log.I("OnRecycled");
			}
			
			public bool IsRecycled { get; set; }

			#endregion
		
			
			#region IPoolType 实现

			public static Msg Allocate()
			{
				return SafeObjectPool<Msg>.Instance.Allocate();
			}
			
			public void Recycle2Cache()
			{
				SafeObjectPool<Msg>.Instance.Recycle(this);
			}
			
			#endregion
		}
		
		private void Start()
		{
			SafeObjectPool<Msg>.Instance.Init(100, 50);			
			
			Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
			
			var fishOne = Msg.Allocate();
			
			Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
			
			fishOne.Recycle2Cache();

			Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
			
			for (int i = 0; i < 10; i++)
			{
				Msg.Allocate();
			}
			
			Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
		}
	}

想进一步了解对象池模式优化原理的同学可以参阅: 对象池模式:http://gpp.tkchu.me/object-pool.html

参考:

     1. 对象池模式:http://gpp.tkchu.me/object-pool.html

     2.Unity 游戏框架搭建 (十九) 简易对象池

     3.Unity 游戏框架搭建 (二十) 更安全的对象池


猜你喜欢

转载自blog.csdn.net/dengshunhao/article/details/80996967