ObjectPool <T> или аналогичный для .NET уже в библиотеке?

Я не хочу писать свои собственные, потому что я боюсь, что могу что-то пропустить и/или разорвать работу других людей, так же есть класс ObjectPool (или аналогичный), существующий в библиотеке .NET?

По пулу объектов я имею в виду класс, который помогает кэшировать объекты, которые занимают много времени для создания, обычно используемые для повышения производительности.

Ответы

Ответ 1

UPDATE:

Я также предложил BufferBlock<T> из TPL DataFlow. IIRC это часть .net сейчас. Самое замечательное в BufferBlock<T> заключается в том, что вы можете ждать асинхронно, чтобы элементы стали доступными с помощью Post<T> и ReceiveAsync<T> методы расширения. Довольно удобно в мире асинхронных/ожидающих.

ОРИГИНАЛЬНЫЙ ОТВЕТ

A назад я столкнулся с этой проблемой и придумал легкий (грубоватый) потокобезопасный (надеюсь) пул, который оказался очень полезным, многоразовым и надежным:

    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();
        }
    }

Чтобы избежать каких-либо требований к интерфейсу объединенных объектов, создание и сброс объектов выполняются предоставленными пользователем делегатами: i.e.

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

В следующей версии .NET(4.0) существует класс ConcurrentBag<T>, который можно легко использовать в ObjectPool<T> реализация; на самом деле есть статья о MSDN, в которой показано, как это сделать.

Если у вас нет доступа к последней платформе .NET, вы можете получить пространство имен System.Collections.Concurrent (которое имеет ConcurrentBag<T>) в .NET 3.5 из Библиотека Microsoft Reactive Extensions (Rx) (в System.Threading.dll).

Ответ 3

CodeProject имеет пример реализации ObjectPool. Посмотрите здесь. В качестве альтернативы существуют некоторые варианты здесь, здесь, и здесь.

Ответ 4

Как насчет System.Collections.Generic.Dictionary?

Ответ 5

Похоже, вам нужен шаблон Factory с кешированием.

Вы можете попробовать использовать рефлектор .net, чтобы посмотреть на реализацию ThreadPool.