Saya berasumsi kode ini memiliki masalah konkurensi:
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;
}
Alasan masalah konkurensi adalah bahwa beberapa utas bisa mendapatkan kunci null dan kemudian mencoba memasukkan data ke cache.
Apa cara terpendek dan terbersih untuk membuat kode ini menjadi bukti konkurensi? Saya suka mengikuti pola yang baik di seluruh kode terkait cache saya. Tautan ke artikel online akan sangat membantu.
MEMPERBARUI:
Saya membuat kode ini berdasarkan jawaban @Scott Chamberlain. Adakah yang bisa menemukan masalah kinerja atau konkurensi dengan ini? Jika berhasil, ini akan menghemat banyak baris kode dan kesalahan.
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>
kunci di mana kuncinya adalah kunci yang sama yang Anda gunakan di Anda MemoryCache
dan objek dalam kamus hanyalah dasar yang Object
Anda kunci. Namun, karena itu, saya akan menyarankan Anda membaca jawaban Jon Hanna. Tanpa pembuatan profil yang tepat Anda mungkin memperlambat program Anda lebih banyak dengan penguncian daripada membiarkan dua contoh SomeHeavyAndExpensiveCalculation()
berjalan dan satu hasil dibuang.
ReaderWriterLockSlim
?