unitycsharp

极简线程安全对象池

2018-12-23  本文已影响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 游戏框架搭建 (二十) 更安全的对象池 - 凉鞋的笔记 - 博客园
上一篇 下一篇

猜你喜欢

热点阅读