21

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

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

4

6 回答 6

23

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

下面的示例演示了如何实现一个以 aSystem.Collections.Concurrent.ConcurrentBag<T>作为其后备存储的对象池。

public class ObjectPool<T>
{
    private ConcurrentBag<T> _objects;
    private Func<T> _objectGenerator;

    public ObjectPool(Func<T> objectGenerator)
    {
        if (objectGenerator == null)
            throw new ArgumentNullException("objectGenerator");
        _objects = new ConcurrentBag<T>();
        _objectGenerator = objectGenerator;
    }

    public T GetObject()
    {
        T item;
        if (_objects.TryTake(out item))
            return item;
        return _objectGenerator();
    }

    public void PutObject(T item)
    {
        _objects.Add(item);
    }
}
于 2009-11-04T05:00:51.013 回答
6

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

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();
}
于 2009-11-04T05:35:07.067 回答
5

没有 Cheeso,没有像这样的通用对象池。但这是个好主意。我认为这将是非常简单的开发。关键是让它在线程环境中运行良好。

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

  1. 保持一个单一的中央对象池。
  2. 保留一个每个线程池(缓存),当它第一次为线程调用时填充,当它变空时。

这样,您可以避免大多数请求的每个线程争用。

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

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

于 2009-11-04T05:03:13.763 回答
2

接受的答案在 2021 年不再正确。

Microsoft.Extensions.ObjectPool NuGet 包,它提供对象池的两种实现DefaultObjectPool<T>LeakTrackingObjectPool<T>

于 2021-01-05T21:43:38.137 回答
1

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

当一个对象被分发时,然后将它从可用列表中删除,将其放入已签出列表中,然后当它返回时,将其反转。

通过为此使用单例,您有一个静态类来调用所有内容,如果昂贵类是单例的内部类,那么没有其他东西可以创建昂贵类,并且您可以轻松控制要创建的对象数量。

于 2009-11-04T04:58:03.750 回答
0

只是为了分享。我使用 Apache Common pool 作为模型创建了一个通用的 .net 公共池库。 http://cobrary.wordpress.com/net-common-pool-library/

于 2013-04-08T06:07:00.097 回答