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

时间:2009-11-09 01:54:37

标签: c# .net

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

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

5 个答案:

答案 0 :(得分:16)

在即将发布的.NET(4.0)版本中,有一个ConcurrentBag<T>类,可以在ObjectPool<T>实现中轻松使用;事实上,there's an article on MSDN向您展示了如何做到这一点。

如果您无权访问最新的.NET框架,则可以从Microsoft's Reactive Extensions (Rx) library(在System中)获取.NET 3.5中的System.Collections.Concurrent命名空间(其中包含ConcurrentBag<T>)。 Threading.dll)。

答案 1 :(得分:12)

更新:

我还提出了来自TPL DataFlow的BufferBlock<T>。 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();
        }
    }

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

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

如果池为空,则BeginPop / EndPop对提供APM(ish)方法,当一个对象可用时异步检索对象(使用Jeff Richter的优秀AsyncResult<TResult>实现)。

我无法完全记住它为什么会被T:class ...那可能没有。

答案 2 :(得分:4)

CodeProject有一个示例ObjectPool实现。看看here。或者,有一些实现hereherehere

答案 3 :(得分:0)

System.Collections.Generic.Dictionary怎么样?

答案 4 :(得分:0)

听起来你需要一个带缓存的工厂模式。

您可以尝试使用.net反射器来查看ThreadPool实现。