Как реализовать блокировку в общем cachecontroller?

#c# #caching #locking

#c# #кэширование #блокировка

Вопрос:

У меня есть статический класс, который обрабатывает чтение / запись кэша для часто используемых данных.

Код такой:

  public static T GetFromCache<T>(double seconds, string cacheId, Func<T> method) where T : class
    {
        HttpContext ctx = HttpContext.Current;
        object temp = null;
        temp = ctx.Cache[cacheId];

        if (temp == null)
        {
            lock (Sync)
            {
                temp = ctx.Cache[cacheId];
                if (temp == null)
                {
                    temp = method.Invoke();
                    AddToCache(temp as T, seconds, cacheId);
                    return temp as T;
                }

            }
        }

        if (temp is T)
        {
            return (T)temp;
        }
        return null;
    }
  

Код используется различными вызывающими устройствами для считывания данных и записи данных в кэш.
Теперь у меня есть объект синхронизации ( private static readonly object Sync = new object(); ), который блокируется при записи данных в кеш.

Поскольку этот код вызывается несколькими вызывающими, я хотел бы создать список объектов синхронизации, по одному для каждого вызывающего. (под вызывающим абонентом я имею в виду не пользователя, а вызывающий код. Тогда я бы идентифицировал a caller по сигнатуре параметра method ) Причина, по которой я этого хочу, заключается в том, что каждый фрагмент вызывающего кода может иметь свой собственный объект блокировки; в противном случае (я думаю) каждый вызов этого cachecontroller от разных вызывающих абонентов будет использовать один и тот же объект блокировки. Тогда кэширование для списка стран также заблокирует кэширование списка состояний, и с двумя разными объектами блокировки они не будут мешать друг другу.

Затем я бы использовал CacheItemRemovedCallback метод для удаления элементов блокировки из списка.

Вопрос заключается в следующем: Как я могу это сделать?

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

1. Возможно ли, чтобы несколько пользователей одновременно выполняли запись в кеш?

2. Да, может быть. Мы также используем его для списков данных для выпадающих списков, поэтому может быть, что 2 пользователя одновременно используют метод

3. Мне трудно понять, зачем вам нужен список объектов синхронизации

4. Я отредактировал вопрос, надеюсь, это прояснит ситуацию

5. Опять же, является ли этот cacheId уникальным глобально или просто уникальным для «вызывающего абонента»?

Ответ №1:

Наличие одного объекта синхронизации для каждого пользователя противоречит цели синхронизации, поскольку каждое использование будет содержать свою собственную блокировку, и есть вероятность, что для одного и того же cacheId вы в конечном итоге вызовете метод несколько раз. Это может привести к непоследовательности данных.

Если вы хотите сохранить один объект синхронизации для каждого пользователя, тогда полезно использовать переменные сеанса или кэш для каждого пользователя или что-то подобное .. в противном случае каждый пользователь будет фактически путать результаты cacheId друг друга.

Если у вас есть сценарий, когда может быть несколько считывателей данных, но одновременно их может записывать один пользователь, попробуйте использовать ReaderWriterLockSlim. Это очень быстро по сравнению с блокировкой в многопользовательском сценарии.

Update1

Учитывая, что cacheId уникален и не распространен среди вызывающих. Вы можете использовать следующий код.

Здесь блокировка не требуется. Причина, HttpContext.Кэш является потокобезопасным. Это означает, что вы можете читать / сохранять значения в кеш. Но, если сама ссылка на значение используется совместно несколькими одновременными вызовами, пожалуйста, синхронизируйте ее.

  public static T GetFromCache<T>(double seconds, string cacheId, Func<T> method) where T : class
        {
            HttpContext ctx = HttpContext.Current;
            object temp = null;
            temp = ctx.Cache[cacheId];
            if (temp == null)
            {
                temp = method.Invoke();
                AddToCache(temp as T, seconds, cacheId);
                return temp as T;
            }
        }
  

С уважением

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

1. Привет, я вижу, мне было не так ясно, что я имел в caller виду; Я отредактировал вопрос для этого.