Нет необходимости блокировать весь экземпляр кеша, вместо этого нам нужно только заблокировать конкретный ключ, который вы вставляете. I.e. Нет необходимости блокировать доступ к туалету для женщин, когда вы используете мужской туалет :)
Нижеприведенная реализация позволяет блокировать определенные ключи кеша, используя параллельный словарь. Таким образом, вы можете запускать GetOrAdd() для двух разных ключей одновременно - но не для одного и того же ключа одновременно.
using System;
using System.Collections.Concurrent;
using System.Web;
using System.Web.Caching;
public static class CacheExtensions
{
private static ConcurrentDictionary<string, object> keyLocks = new ConcurrentDictionary<string, object>();
/// <summary>
/// Get or Add the item to the cache
/// </summary>
public static T GetOrAdd<T>(this Cache cache, string key, Func<T> factory, int durationInSeconds, bool synchronised = true)
where T : class
{
// Try and get value from the cache
var value = cache.Get(key);
if (value == null)
{
// If not yet cached, lock the key value and add to cache
lock (keyLocks.GetOrAdd(key, new object()))
{
// Try and get from cache again in case it has been added in the meantime
value = HttpRuntime.Cache.Get(key);
if (value == null && (value = factory()) != null)
{
HttpRuntime.Cache.Insert(key,
value,
null,
DateTime.Now.AddSeconds(durationInSeconds),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null);
}
// Remove temporary key lock
object locker;
keyLocks.TryRemove(key, out locker);
}
}
return value as T;
}
}
Если первая загрузка кэша занимает несколько минут, есть еще способ доступа к записи уже загружены? Скажем, если у меня есть GetFoo_AmazonArticlesByCategory (строка categoryKey). Наверное, это будет что-то вроде блокировки для категорииKey. – 2009-06-23 17:54:32
Называется «двойная проверка». http://en.wikipedia.org/wiki/Double-checked_locking – 2013-01-24 18:13:40