美文网首页unitycsharp
极简线程安全对象池

极简线程安全对象池

作者: 雨落随风 | 来源:发表于2018-12-23 03:01 被阅读0次

    本来想在重构 Timer 时候的使用,但是为了保留链式编程风格,就还是没能把这个对象池用上。但写了半天,扔掉可惜了,写在这里呢,希望能对读者有啥启发最好了。

    核心代码

    using System;
    using System.Collections.Concurrent;
    public interface IPoolable
    {
        /// <summary>
        /// 对象池 用于标记层别是否可被回收
        /// </summary>
        AllocateState AllocateState { get; set; }
    }
    public enum AllocateState
    {
         InUse,//使用中
         Recycled //已回收
    }
    
    public sealed class ObjectPool<T> where T : IPoolable 
    {
        internal ConcurrentStack<T> items; //线程安全 栈
        private Func<T> factory; //埋入的实例化 规则
        public int Count //池子有多少货
        {
            get
            {
                return items.Count;
            }
        }
        public int Capacity { get; set; } //池子有多大
    
        internal ObjectPool(Func<T> factory,int capacity = 100)
        {
            this.factory = factory;
            this.Capacity = capacity;
            items = new ConcurrentStack<T>();
        }
        public void Clear()
        {
            items.Clear();
        }
        public T Allocate() //分配
        {
            T item = default(T);
            if (items.IsEmpty || !items.TryPop(out item))
            {
                item =factory.Invoke();
            }
            item.AllocateState = AllocateState.InUse; //标记为使用中
            return item;
        }
        public void Release(T target) //释放
        {
            //池爆炸了再多都不再要了,当然,如果不是 InUse 的就更别想挤进来~
            if (target.AllocateState.Equals(AllocateState.InUse) && items.Count < Capacity) 
            {
                items.Push(target);
            }
        }
    }
    

    Tips:

    1. 使用了泛型 T 实现了类型安全;
    2. 使用了 ConcurrentStack 线程安全栈,微软底层帮处理了可能存在的并发问题 ;
    3. 控制反转 : Func<T> factory ,可以预先埋入实例化逻辑,
    4. 使用 IPoolable 接口标记可回收的对象

    使用场景(伪代码)

    public class A : IPoolable  //这个是可回收对象
    {
        public AllocateState AllocateState{get;set;}
        public string feild;
        public void RestData() // 重置数据
        {
            feild = string.Empty;
        }
    }
    
    public class B  //这个类 演示了怎么使用这个 对象池
    {
        public void Test()
        {
            ObjectPool<A> pool = new ObjectPool<A>(InstantiateRule); //造个池子,埋入实例化规则
            A a = pool.Allocate(); //分配对象
            a.feild = "假装在使用这个对象";
            a.RestData(); //重置数据准备回收啦
            pool.Release(a); //回收到对象池
        }
        private A InstantiateRule()//实例化规则
        {
            return new A(); //当然可以写更多定制化的东西在里面
        }
    }
    

    扩展阅读:

    1. GitHub/UnityCsReference/ObjectPool.cs (Unity官方公开的源码)
    2. System.Reflection.Internal.ObjectPool<T>
    3. C# 队列和栈 线程安全 - 天才卧龙 - 博客园
    4. Unity 游戏框架搭建 (二十) 更安全的对象池 - 凉鞋的笔记 - 博客园

    相关文章

      网友评论

        本文标题:极简线程安全对象池

        本文链接:https://www.haomeiwen.com/subject/ccrgkqtx.html