.NET中已存在ObjectPool <T>或类似内容?

RCI*_*CIX 14 .net c#

我不想写自己的,因为我担心我可能会遗漏某些东西和/或扯掉其他人的工作,那么.NET库中是否存在ObjectPool(或类似)类?

对象池,我指的是一个帮助缓存需要很长时间才能创建的对象的类,通常用于提高性能.

Dan*_*Tao 16

在即将推出的.NET(4.0)版本中,有一个ConcurrentBag<T>类可以很容易地在ObjectPool<T>实现中使用; 事实上,有一篇关于MSDN的文章向您展示了如何做到这一点.

如果您无法访问最新的.NET框架,则可以从Microsoft的Reactive Extensions(Rx)库(在System.Threading.dll中)获取.NET 3.5中的System.Collections.Concurrent命名空间(具有).ConcurrentBag<T>


spe*_*der 12

更新:

我也是BufferBlock<T>从TPL DataFlow 提出来的.IIRC现在是.net的一部分.最棒的BufferBlock<T>是,您可以使用Post<T>ReceiveAsync<T>扩展方法异步等待项目变为可用.在异步/等待世界中非常方便.

原始答案

前一阵子我遇到了这个问题,想出了一个轻量级(粗糙'已经)线程安全(我希望)的游泳池,它已被证明非常有用,可重复使用且功能强大:

    public class Pool<T> where T : class
    {
        private readonly Queue<AsyncResult<T>> asyncQueue = new Queue<AsyncResult<T>>();
        private readonly Func<T> createFunction;
        private readonly HashSet<T> pool;
        private readonly Action<T> resetFunction;

        public Pool(Func<T> createFunction, Action<T> resetFunction, int poolCapacity)
        {
            this.createFunction = createFunction;
            this.resetFunction = resetFunction;
            pool = new HashSet<T>();
            CreatePoolItems(poolCapacity);
        }

        public Pool(Func<T> createFunction, int poolCapacity) : this(createFunction, null, poolCapacity)
        {
        }

        public int Count
        {
            get
            {
                return pool.Count;
            }
        }

        private void CreatePoolItems(int numItems)
        {
            for (var i = 0; i < numItems; i++)
            {
                var item = createFunction();
                pool.Add(item);
            }
        }

        public void Push(T item)
        {
            if (item == null)
            {
                Console.WriteLine("Push-ing null item. ERROR");
                throw new ArgumentNullException();
            }
            if (resetFunction != null)
            {
                resetFunction(item);
            }
            lock (asyncQueue)
            {
                if (asyncQueue.Count > 0)
                {
                    var result = asyncQueue.Dequeue();
                    result.SetAsCompletedAsync(item);
                    return;
                }
            }
            lock (pool)
            {
                pool.Add(item);
            }
        }

        public T Pop()
        {
            T item;
            lock (pool)
            {
                if (pool.Count == 0)
                {
                    return null;
                }
                item = pool.First();
                pool.Remove(item);
            }
            return item;
        }

        public IAsyncResult BeginPop(AsyncCallback callback)
        {
            var result = new AsyncResult<T>();
            result.AsyncCallback = callback;
            lock (pool)
            {
                if (pool.Count == 0)
                {
                    lock (asyncQueue)
                    {
                        asyncQueue.Enqueue(result);
                        return result;
                    }
                }
                var poppedItem = pool.First();
                pool.Remove(poppedItem);
                result.SetAsCompleted(poppedItem);
                return result;
            }
        }

        public T EndPop(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<T>) asyncResult;
            return result.EndInvoke();
        }
    }
Run Code Online (Sandbox Code Playgroud)

为了避免池化对象的任何接口要求,对象的创建和重置都由用户提供的委托执行:即

Pool<MemoryStream> msPool = new Pool<MemoryStream>(() => new MemoryStream(2048), pms => {
        pms.Position = 0;
        pms.SetLength(0);
    }, 500);
Run Code Online (Sandbox Code Playgroud)

在池为空的情况下,BeginPop/EndPop对提供了一种APM(ish)方法,当一个对象可用时异步检索对象(使用Jeff Richter出色的AsyncResult <TResult>实现).

我不太清楚为什么它会被T:class ...那可能没有.