...

вторник, 21 мая 2019 г.

Универсальный пул

У нас есть ArrayPool для переиспользования массивов. Работает это так: взяли массив определенной длинны что то с ним поделали и положили обратно. Нужно это для больших объектов которые по логике программы долго не должны храниться. В предыдущей статье описана эта проблема.

Так же могут понадобиться не только массивы, поэтому попробуем написать универсальный пул.

Нам понадобится хранилище для элементов ConcurrentBag и методы для создания и очистки элемента в хранилище.

    public sealed class Pool<T>
    {
        private ConcurrentBag<T> _items =
            new ConcurrentBag<T>();

        private readonly Func<T> _itemCreator = null;
        private readonly Action<T> _itemClearer = null;

        public Pool(Func<T> itemCreator)
        {
            _itemCreator = itemCreator ?? throw new ArgumentNullException("itemCreator");
        }

        public Pool(Func<T> itemCreator, Action<T> itemClearer) : this(itemCreator)
        {
            _itemClearer = itemClearer ?? throw new ArgumentNullException("itemClearer");
        }

        public T Rent()
        {
            if (_items.TryTake(out var item))
                return item;

            return _itemCreator();
        }

        public void Return(T item)
        {
            _itemClearer?.Invoke(item);

            _items.Add(item);
        }

        public int Count()
        {
            return _items.Count;
        }
    }

Метод Rent берет элемент или создает, а метод Return возвращает в ConcurrentBag, перед этим очистив его если это требуется.

Конструктор с одним параметром означает что элементы не будут очищаться.

Приведу пример для List:

       var bigListPool = new Pool<List<long>>(Creator, Clearer);

       List<long> list = null;

       try
       {
          list = bigListPool.Rent();
          //тут работа с list
       }
       finally
       {
         if (list != null)
             bigListPool.Return(list);
       }

Создание и очистка List:

        List<long> Creator() => new List<long>(1024 * 1024);

        void Clearer(List<long> l) => l.ForEach(i => i = 0);

Если список другого размера то надо создать еще один пул. Далее можно все это дело обернуть и внедрить синглтоном через ConfigureServices.

Проект

Let's block ads! (Why?)

Комментариев нет:

Отправить комментарий