Bu kodun eşzamanlılık sorunları olduğunu varsayıyorum:
const string CacheKey = "CacheKey";
static string GetCachedData()
{
string expensiveString =null;
if (MemoryCache.Default.Contains(CacheKey))
{
expensiveString = MemoryCache.Default[CacheKey] as string;
}
else
{
CacheItemPolicy cip = new CacheItemPolicy()
{
AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes(20))
};
expensiveString = SomeHeavyAndExpensiveCalculation();
MemoryCache.Default.Set(CacheKey, expensiveString, cip);
}
return expensiveString;
}
Eşzamanlılık sorununun nedeni, birden çok iş parçacığının bir boş anahtar alabilmesi ve ardından önbelleğe veri eklemeye çalışabilmesidir.
Bu kod eşzamanlılığını kanıtlamanın en kısa ve en temiz yolu nedir? Önbellekle ilgili kodumda iyi bir model izlemeyi seviyorum. Çevrimiçi bir makaleye bağlantı çok yardımcı olacaktır.
GÜNCELLEME:
Bu kodu @ Scott Chamberlain'in cevabına dayanarak buldum. Bununla ilgili herhangi bir performans veya eşzamanlılık sorunu bulabilen var mı? Bu işe yararsa, birçok satır kod ve hatayı kaydeder.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Caching;
namespace CachePoc
{
class Program
{
static object everoneUseThisLockObject4CacheXYZ = new object();
const string CacheXYZ = "CacheXYZ";
static object everoneUseThisLockObject4CacheABC = new object();
const string CacheABC = "CacheABC";
static void Main(string[] args)
{
string xyzData = MemoryCacheHelper.GetCachedData<string>(CacheXYZ, everoneUseThisLockObject4CacheXYZ, 20, SomeHeavyAndExpensiveXYZCalculation);
string abcData = MemoryCacheHelper.GetCachedData<string>(CacheABC, everoneUseThisLockObject4CacheXYZ, 20, SomeHeavyAndExpensiveXYZCalculation);
}
private static string SomeHeavyAndExpensiveXYZCalculation() {return "Expensive";}
private static string SomeHeavyAndExpensiveABCCalculation() {return "Expensive";}
public static class MemoryCacheHelper
{
public static T GetCachedData<T>(string cacheKey, object cacheLock, int cacheTimePolicyMinutes, Func<T> GetData)
where T : class
{
//Returns null if the string does not exist, prevents a race condition where the cache invalidates between the contains check and the retreival.
T cachedData = MemoryCache.Default.Get(cacheKey, null) as T;
if (cachedData != null)
{
return cachedData;
}
lock (cacheLock)
{
//Check to see if anyone wrote to the cache while we where waiting our turn to write the new value.
cachedData = MemoryCache.Default.Get(cacheKey, null) as T;
if (cachedData != null)
{
return cachedData;
}
//The value still did not exist so we now write it in to the cache.
CacheItemPolicy cip = new CacheItemPolicy()
{
AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes(cacheTimePolicyMinutes))
};
cachedData = GetData();
MemoryCache.Default.Set(cacheKey, cachedData, cip);
return cachedData;
}
}
}
}
}
Dictionary<string, object>
anahtarın sizde kullandığınız anahtarla aynı MemoryCache
olduğu ve sözlükteki nesnenin Object
kilitlediğiniz temel bir nesne olduğu bir ortamda kolayca yapılabilir . Ancak, Jon Hanna'nın cevabını okumanızı tavsiye ederim. Doğru profilleme olmadan, programınızı kilitleme ile iki çalışma örneğine izin vermektense SomeHeavyAndExpensiveCalculation()
ve bir sonucun atılmasına izin vermekten daha fazla yavaşlatıyor olabilirsiniz .
ReaderWriterLockSlim
?