#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
виду; Я отредактировал вопрос для этого.