Tôi giả sử mã này có vấn đề về đồng thời:
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;
}
Lý do cho vấn đề đồng thời là nhiều luồng có thể nhận được một khóa null và sau đó cố gắng chèn dữ liệu vào bộ nhớ cache.
Cách ngắn nhất và rõ ràng nhất để làm cho mã này bằng chứng đồng thời là gì? Tôi muốn làm theo một mô hình tốt trên mã liên quan đến bộ nhớ cache của mình. Một liên kết đến một bài báo trực tuyến sẽ là một trợ giúp tuyệt vời.
CẬP NHẬT:
Tôi đã nghĩ ra mã này dựa trên câu trả lời của @Scott Chamberlain. Bất cứ ai có thể tìm thấy bất kỳ vấn đề hiệu suất hoặc đồng thời với điều này? Nếu điều này hoạt động, nó sẽ lưu nhiều dòng mã và lỗi.
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>
khóa trong đó chính là khóa bạn sử dụng trong của mình MemoryCache
và đối tượng trong từ điển chỉ là đối tượng cơ bản Object
mà bạn khóa. Tuy nhiên, điều đó đang được nói ra, tôi khuyên bạn nên đọc qua câu trả lời của Jon Hanna. Nếu không có cấu hình thích hợp, bạn có thể làm chậm chương trình của mình nhiều hơn với việc khóa hơn là để hai trường hợp SomeHeavyAndExpensiveCalculation()
chạy và có một kết quả bị loại bỏ.
ReaderWriterLockSlim
?