Класс возник по результату трасировки приложения, оказалось что есть куча дублирующих запросов, трассировка выполнялась с помощью http://miniprofiler.com/, получил целую кучу дублированных запросов. Написал этот кэш менеджер, вместо 42 сек. получил время загрузки 3 секунды.
Примеры вызова:
// время кэширования 3 сек. количество элементов 100, фоновая очистка включена
OneTimeCash cash = new OneTimeCash(3,100,true);
// время кэширования 400 сек. количество элементов 100, фоновая очистка выключена
var cashe1 = new OneTimeCash(400, 100, false);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace OneTimeCach
{
///
/// Кэширование предмета 1 раз. Используется для тяжелых операций типа обращения к БД
///
///тип кэшируемого значения
public class OneTimeCash
{
///
///Конструктор класса с инициализацией параметров по умолчанию.
///
/// интервал очистки старых элементов в кэше по умолчанию 5 секунд
/// Максимальное значение элементов в кэше
/// Запускать очистку в фоновом потоке по умолчанию false, в этом случае очистка происходит при вставке элемента
public OneTimeCash(int duration = 5, int maxcount = 100, bool backgroundCleanup = false)
{
this.duration = duration;
this.isBackgroundCleanup = backgroundCleanup;
this.maxCount = maxcount;
this.items = new List(maxCount);
if (isBackgroundCleanup)
{
isALive = true;
Thread thread = new Thread(new ThreadStart(CleanapThreadWorker));
thread.Start();
}
}
///
/// Закрываем поток очистки кэша
///
~OneTimeCash()
{
this.isALive = false;
}
///
/// Процедура фоновой очистки кэша
///
void CleanapThreadWorker()
{
while (isALive)
{
Thread.Sleep(new TimeSpan(0, 0, duration));
Cleanup();
}
}
///
/// Контейнер для кэшируемых данных
///
private class Container
{
///
/// Времф создания или обновления обьекта в кэше
///
public DateTime Updated;
///
/// Ключ для кэшированного обьекта
///
public string Key;
///
/// Кэшированный обьект
///
public T Value;
}
///
/// Флаг фонового очищения данных кэша
///
bool isBackgroundCleanup;
///
/// Флаг указывающий на необходимость работы фоновой очистки данных
///
bool isALive;
public bool IsAlive { get { return isALive; } set { isALive = value; } }
///
/// Промежуток времени жизни обьектов в кэше
///
int duration;
///
/// Максимальное количество обьектов в кэше
///
int maxCount;
///
/// Контейнер для хранения кэшированных обьектов
///
List items;
///
/// Обьект блокировки
///
object locker = new object();
///
/// Помещает элемент в кэш, и производит очистку устаревших элементов если не установлена автоочистка
///
/// Ключ для сохранения кэшированного обьекта
/// Кэшируемый обьект
public void PutItem(string key, T cashedObject)
{
var item = items.FirstOrDefault(x => x.Key == key);
if (item != null)
{
item.Updated = DateTime.Now;
item.Value = cashedObject;
}
else
{
lock (locker)
{
items.Add(new Container() { Key = key, Value = cashedObject, Updated = DateTime.Now });
}
}
if (items.Count > maxCount )
{
Cleanup();
}
}
///
/// Очистка от устаревших элементов кэша
///
private void Cleanup()
{
var result = (from sel in items
where sel.Updated > DateTime.Now.AddSeconds(-duration)
orderby sel.Updated descending
select sel).Take(maxCount);
List container = new List(maxCount);
container.AddRange(result);
lock (locker)
{
items = container;
}
}
///
/// Проверяет наличие обьекта в кэше
///
/// Ключ для поиска
///
public bool IsItemInCache(string key)
{
return items.Any(x => x.Key == key);
}
///
/// Получаем закешированный обьект
///
/// Ключ для получения кэшированного обьекта
///Возникает когда обьекта нет в кэше
///
public T GetItem(string key)
{
var item = items.FirstOrDefault(x => x.Key == key);
if (item != null)
{
return item.Value;
}
else
{
throw new ArgumentException(string.Format("No cashed object: {0}", key));
}
}
}
}
Примеры вызова:
// время кэширования 3 сек. количество элементов 100, фоновая очистка включена
OneTimeCash
// время кэширования 400 сек. количество элементов 100, фоновая очистка выключена
var cashe1 = new OneTimeCash
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace OneTimeCach
{
///
/// Кэширование предмета 1 раз. Используется для тяжелых операций типа обращения к БД
///
///
public class OneTimeCash
{
///
///Конструктор класса с инициализацией параметров по умолчанию.
///
/// интервал очистки старых элементов в кэше по умолчанию 5 секунд
/// Максимальное значение элементов в кэше
/// Запускать очистку в фоновом потоке по умолчанию false, в этом случае очистка происходит при вставке элемента
public OneTimeCash(int duration = 5, int maxcount = 100, bool backgroundCleanup = false)
{
this.duration = duration;
this.isBackgroundCleanup = backgroundCleanup;
this.maxCount = maxcount;
this.items = new List
if (isBackgroundCleanup)
{
isALive = true;
Thread thread = new Thread(new ThreadStart(CleanapThreadWorker));
thread.Start();
}
}
///
/// Закрываем поток очистки кэша
///
~OneTimeCash()
{
this.isALive = false;
}
///
/// Процедура фоновой очистки кэша
///
void CleanapThreadWorker()
{
while (isALive)
{
Thread.Sleep(new TimeSpan(0, 0, duration));
Cleanup();
}
}
///
/// Контейнер для кэшируемых данных
///
private class Container
{
///
/// Времф создания или обновления обьекта в кэше
///
public DateTime Updated;
///
/// Ключ для кэшированного обьекта
///
public string Key;
///
/// Кэшированный обьект
///
public T Value;
}
///
/// Флаг фонового очищения данных кэша
///
bool isBackgroundCleanup;
///
/// Флаг указывающий на необходимость работы фоновой очистки данных
///
bool isALive;
public bool IsAlive { get { return isALive; } set { isALive = value; } }
///
/// Промежуток времени жизни обьектов в кэше
///
int duration;
///
/// Максимальное количество обьектов в кэше
///
int maxCount;
///
/// Контейнер для хранения кэшированных обьектов
///
List
///
/// Обьект блокировки
///
object locker = new object();
///
/// Помещает элемент в кэш, и производит очистку устаревших элементов если не установлена автоочистка
///
/// Ключ для сохранения кэшированного обьекта
/// Кэшируемый обьект
public void PutItem(string key, T cashedObject)
{
var item = items.FirstOrDefault(x => x.Key == key);
if (item != null)
{
item.Updated = DateTime.Now;
item.Value = cashedObject;
}
else
{
lock (locker)
{
items.Add(new Container() { Key = key, Value = cashedObject, Updated = DateTime.Now });
}
}
if (items.Count > maxCount )
{
Cleanup();
}
}
///
/// Очистка от устаревших элементов кэша
///
private void Cleanup()
{
var result = (from sel in items
where sel.Updated > DateTime.Now.AddSeconds(-duration)
orderby sel.Updated descending
select sel).Take(maxCount);
List
container.AddRange(result);
lock (locker)
{
items = container;
}
}
///
/// Проверяет наличие обьекта в кэше
///
/// Ключ для поиска
///
public bool IsItemInCache(string key)
{
return items.Any(x => x.Key == key);
}
///
/// Получаем закешированный обьект
///
/// Ключ для получения кэшированного обьекта
///
///
public T GetItem(string key)
{
var item = items.FirstOrDefault(x => x.Key == key);
if (item != null)
{
return item.Value;
}
else
{
throw new ArgumentException(string.Format("No cashed object: {0}", key));
}
}
}
}
Комментариев нет:
Отправить комментарий