Как заблокировать ключ кеша?

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

Он должен выглядеть примерно так:

//private static readonly lockObject = new Object();

public T GetCache<T>(string key, Func<T> valueFactory...)
{

  // try to pull from cache here

  lock (lockObject) // I don't want to use static object lock here because then every time a lock is performed, all cached objects in my site have to wait, regarding of the cache key.
  {
    // cache was empty before we got the lock, check again inside the lock

    // cache is still empty, so retreive the value here

    // store the value in the cache here
  }

  // return the cached value here

}

Ответ 1

Первый ответ

Это тот случай, когда вы используете мьютекс

public T GetCache<T>(string key, Func<T> valueFactory...) 
{
    // note here that I use the key as the name of the mutex
    // also here you need to check that the key have no invalid charater
    //   to used as mutex name.
    var mut = new Mutex(true, key);

    try
    {   
        // Wait until it is safe to enter.
        mut.WaitOne();

        // here you create your cache
    }
    finally
    {
        // Release the Mutex.
        mut.ReleaseMutex();
    }   
}

Дополнительная информация

Для блокировки есть два случая.

1) Один случай - когда мы используем общие ресурсы во всех пулах, все потоки. Общий ресурс может быть файлом или базой данных.

В общих ресурсах нам нужно использовать мьютекс.

2) Второй случай - когда мы используем переменные, видимые только внутри пула - разные пулы не могут видеть эти ресурсы. Например, статический список <>, статический словарь и т.д. Эти статические переменные, массивы могут иметь доступ только внутри пула, и они не одинаковы для разных пулов.

В этом втором случае lock() является самым простым и распространенным способом использования.

Быстрее, чем блокировка

Теперь, когда у нас есть статический словарь, который мы сохраняем в течение длительного времени и делаем слишком много ReaderWriterLockSlim чтения/записи, более быстрый подход, чтобы избежать полной программы для ожидания, - это ReaderWriterLockSlim

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

Что такое пул в asp.net.

Изображения, как будто разные программы, которые работают, изолируют друг друга, но обслуживают входящие запросы от пользователей. У каждого пула есть свой мир, и они не общаются друг с другом. Каждый пул имеет свою инициализацию, свои статические ценности и свою жизнь. Чтобы иметь общий ресурс между пулами, вам нужна какая-то другая третья программа, например база данных, такая как файл на диске, как услуга.

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

Пулы приложений IIS, рабочие процессы, домены приложений
Пожизненная статическая переменная ASP.NET

Ответ 2

Я только что нашел LazyCache lib. Я еще не пробовал его в производстве.

IAppCache cache = new CachingService();
ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
    () => methodThatTakesTimeOrResources());

Ответ 3

.NET ConcurrentDictionary<TKey, TItem> реализует это внутренне, создавая отдельный замок для каждого хэша ключа. Это имеет преимущество только для блокировки одного соответствующего хэша, даже при обработке и удалении элементов.