C# 是否有用于.NET的通用对象池?

C# 是否有用于.NET的通用对象池?,c#,.net,object-pooling,C#,.net,Object Pooling,就时间和内存而言,我有一个构建成本很高的类。我想维护这些东西的一个池,并根据需要将它们分发给同一进程中的多个线程 是否有已经过测试和验证的通用对象池?(我不想要COM+池。)为什么不编写一个单例,作为已创建对象数组的网关呢 分发对象时,将其从可用列表中删除,放入签出列表中,然后在返回对象时,将其反转 通过使用单例,您可以为所有要调用的对象创建一个静态类,如果昂贵的类是单例的内部类,那么其他任何东西都无法创建昂贵的类,并且您可以轻松控制要创建多少对象。直接从MSDN中提取,下面是在.NET 4中使

就时间和内存而言,我有一个构建成本很高的类。我想维护这些东西的一个池,并根据需要将它们分发给同一进程中的多个线程


是否有已经过测试和验证的通用对象池?(我不想要COM+池。)

为什么不编写一个单例,作为已创建对象数组的网关呢

分发对象时,将其从可用列表中删除,放入签出列表中,然后在返回对象时,将其反转


通过使用单例,您可以为所有要调用的对象创建一个静态类,如果昂贵的类是单例的内部类,那么其他任何东西都无法创建昂贵的类,并且您可以轻松控制要创建多少对象。

直接从MSDN中提取,下面是在.NET 4中使用一种新的并发集合类型的示例:

下面的示例演示如何实现以作为其备份存储的对象池

公共类对象池
{
私有ConcurrentBag_对象;
私有函数对象生成器;
公共对象池(Func对象生成器)
{
if(objectGenerator==null)
抛出新ArgumentNullException(“objectGenerator”);
_对象=新的ConcurrentBag();
_objectGenerator=objectGenerator;
}
公共T GetObject()
{
T项;
如果(_objects.TryTake(out项))
退货项目;
返回_objectGenerator();
}
公共对象(T项)
{
_对象。添加(项);
}
}

不,所以,没有像这样的通用对象池。但这是个好主意。我认为这将是非常简单的发展。关键是让它在线程化环境中很好地工作

我认为这是一个有趣的设计问题。例如,如果这需要在服务器类硬件上进行扩展,并且您将经常将对象提供给indivudual线程,那么您可以这样做:

  • 保持一个单一的中央对象池
  • 保留一个每线程池(缓存),该池在第一次为线程调用时以及当它变为空时填充
  • 通过这种方式,可以避免大多数请求的每线程争用

    不同的操作条件将导致不同的设计。例如,如果对象分配很少或线程数较低,那么在集合周围设置锁可能更简单。这不会很好地扩展,但在这种情况下,它需要


    如果正确设计了类或接口,则可以随着时间的推移更改实现以处理更复杂的场景。

    280Z28提出的ObjectPool类看起来相当不错。您还可以考虑创建另一个类,该类实现IDISPosibe并包装GETObjutter()的返回值。这将确保对象返回到您的池中,并且可以很好地读取:

    class ObjectPoolReference<T> : IDisposable
    {
        public ObjectPool<T> Pool { get; private set; }
    
        public T Instance { get; private set; }
    
        public ObjectPoolReference(ObjectPool<T> pool, T instance)
        {
            Pool = pool;
            Instance = instance;
        }
    
        ~ObjectPoolReference()
        {
            Dispose();
        }
    
        #region IDisposable Members
    
        private bool _Disposed = false;
    
        public void Dispose()
        {
            if (!_Disposed)
            {
                Pool.PutObject(Instance);
    
                _Disposed = true;
            }
        }
    
        #endregion
    }
    
    //instance of the pool
    ObjectPool<Foo> Pool;
    
    //"using" ensures the reference is disposed at the end of the block, releasing the object back to the pool
    using (var Ref = Pool.GetObject())
    {
        Ref.Instance.DoSomething();
    }
    
    class ObjectPoolReference:IDisposable
    {
    公共对象池池{get;private set;}
    公共T实例{get;私有集;}
    公共ObjectPoolReference(ObjectPool池,T实例)
    {
    池=池;
    实例=实例;
    }
    ~ObjectPoolReference()
    {
    处置();
    }
    #区域IDisposable成员
    private bool_Disposed=false;
    公共空间处置()
    {
    如果(!\u已处置)
    {
    PutObject(实例);
    _这是真的;
    }
    }
    #端区
    }
    //池的实例
    对象池池;
    //“使用”确保在块的末尾处理引用,将对象释放回池中
    使用(var Ref=Pool.GetObject())
    {
    参考实例DoSomething();
    }
    
    只是为了分享。我使用Apache公共池作为模型创建了一个通用的.net公共池库

    公认的答案在2021年不再正确


    还有一个NuGet包,它提供了对象池
    DefaultObjectPool
    LeakTrackingObjectPool

    的两个实现。谢谢,我看到了这个。这取决于.NET4.0。不幸的是,我依赖于NET2.0!!!林克,也许:是的,那会有用的。对象池可以非常简单。但是还有一些额外的细节,比如有界对象总体(不低于x,不高于y)、命名对象、对象属性等等。我只是想知道是否有人已经设计了它并考虑了这些东西。@Cheeso-你可能想把它添加到你的问题中,因为它会大大改变这个问题。
    class ObjectPoolReference<T> : IDisposable
    {
        public ObjectPool<T> Pool { get; private set; }
    
        public T Instance { get; private set; }
    
        public ObjectPoolReference(ObjectPool<T> pool, T instance)
        {
            Pool = pool;
            Instance = instance;
        }
    
        ~ObjectPoolReference()
        {
            Dispose();
        }
    
        #region IDisposable Members
    
        private bool _Disposed = false;
    
        public void Dispose()
        {
            if (!_Disposed)
            {
                Pool.PutObject(Instance);
    
                _Disposed = true;
            }
        }
    
        #endregion
    }
    
    //instance of the pool
    ObjectPool<Foo> Pool;
    
    //"using" ensures the reference is disposed at the end of the block, releasing the object back to the pool
    using (var Ref = Pool.GetObject())
    {
        Ref.Instance.DoSomething();
    }