Обеспечение безопасности потоков с помощью кэша ASP.Net - рассказ о двух стратегиях

1

У меня есть код, который не является потокобезопасным:

public byte[] GetImageByteArray(string filepath, string contentType, RImgOptions options)
{               
    //Our unique cache keys will be composed of both the image filepath and the requested width
    var cacheKey = filepath + options.Width.ToString();
    var image = HttpContext.Current.Cache[cacheKey];

    //If there is nothing in the cache, we need to generate the image, insert it into the cache, and return it
    if (image == null)
    {
        RImgGenerator generator = new RImgGenerator();
        byte[] bytes = generator.GenerateImage(filepath, contentType, options);
        CacheItem(cacheKey, bytes);
        return bytes;
    }
    //Image already exists in cache, serve it up!
    else
    {
        return (byte[])image;
    }
}

Мой CacheItem() проверяет, достигнут ли максимальный размер кеша, и если он есть, он начнет удаление кэшированных элементов:

//If the cache exceeds its max allotment, we will remove items until it falls below the max
while ((int)cache[CACHE_SIZE] > RImgConfig.Settings.Profile.CacheSize * 1000 * 1000)
{
    var entries = (Dictionary<string, DateTime>)cache[CACHE_ENTRIES];
    var earliestCacheItem = entries.SingleOrDefault(kvp => kvp.Value == entries.Min(d => d.Value));
    int length = ((byte[])cache[earliestCacheItem.Key]).Length;
    cache.Remove(earliestCacheItem.Key);
    cache[CACHE_SIZE] = (int)cache[CACHE_SIZE] - length;
}

Поскольку один поток может удалить элемент из кеша, поскольку другой поток ссылается на него, я могу представить два варианта:

Вариант 1: блокировка

lock (myLockObject)
{
    if(image == null){ **SNIP** }
}

Вариант 2. Назначьте мелкую копию локальной переменной

var image = HttpContext.Current.Cache[cacheKey] != null ? HttpContext.Current.Cache[cacheKey].MemberwiseClone() : null;

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

Есть ли другие стратегии, которые я мог бы использовать здесь?

  • 0
    Я не вижу проблемы с этим кодом. Насколько я могу судить, удаление элемента из кэша не избавляет от него. Таким образом, удаление его из кэша только удаляет ссылку. Объект, ссылающийся на него, не должен быть затронут, если вы явно не избавляетесь от него. Сам кэш является поточно-ориентированным, поэтому вам не нужно беспокоиться об удалении объекта во время его поиска.
  • 0
    Вы также знаете, что можете установить максимальный размер кэша в вашем файле web.config? И когда этот размер будет достигнут, asp.net сам начнет обрезать кеш? Я не уверен, почему вы чувствуете необходимость сделать это самостоятельно ...
Показать ещё 4 комментария
Теги:
multithreading

1 ответ

0
Лучший ответ

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

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

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

Просто проверьте, какой из них лучше подходит вашему типу BL и используйте его. Он не удалит проблему блокировки вообще, но правильный выбор значительно устранит гоночные условия.

Чтобы уменьшить общий ресурс между различными потоками, используйте блокировки чтения и записи для каждого элемента, а не для всей коллекции. Это также повысит вашу производительность.

Еще один момент рассмотрения, который следует иметь в виду: что, если содержание изображения с одним и тем же путем физически изменяется на диске (другое изображение было сохранено с тем же именем), при том, что это изображение уже кэшировано, есть вероятность ошибочного предоставления не Соответствующие данные.

Надеюсь, это помогло.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню