我有以下带缓存的存储库
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
public interface IUserRepository
{
User GetUser(int userId);
}
public class CacheObject
{
public int UserId { get; set; }
public User User { get; set; }
public DateTime CreationDate { get; set; }
}
public class CachedUserRepository : IUserRepository
{
private IUserRepository _userRepository;
private List<CacheObject> _cache = new List<CacheObject>();
private int _cacheDuration = 60;
public CachedUserRepository(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public User GetUser(int userId)
{
bool addToCache = false;
CacheObject valueFromCache = _cache.SingleOrDefault(u => u.UserId == userId);
// user was found
if (valueFromCache != null)
{
// if cache is outdated then remove value from it
if (valueFromCache.CreationDate.AddSeconds(_cacheDuration) < DateTime.Now)
{
_cache.Remove(valueFromCache);
addToCache = true;
}
else {
// update cache date
valueFromCache.CreationDate = DateTime.Now;
return valueFromCache.User;
}
}
// user is absent in cache
else {
addToCache = true;
}
if (addToCache)
{
User result = _userRepository.GetUser(userId);
_cache.Add(new CacheObject() { User = result, UserId = userId, CreationDate = DateTime.Now });
return result;
}
return null;
}
}
我想在不同的线程中运行方法GetUser(),所以我需要使这个方法线程安全。
我该怎么做?
我没有看到任何优雅的解决方案,只有lock(someObject)到整个方法体。但结果我不会获得任何性能提升
答案 0 :(得分:0)
我们通常使用ReaderWriterLockSlim这样做:
public class CachedUserRepository : IUserRepository
{
private readonly ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private IUserRepository _userRepository;
private List<CacheObject> _cache = new List<CacheObject>();
private int _cacheDuration = 60;
public CachedUserRepository(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public User GetUser(int userId)
{
bool addToCache = false;
// Enter an upgradeable read lock because we might have to use a write lock if having to update the cache
// Multiple threads can read the cache at the same time
_cacheLock.EnterUpgradeableReadLock();
try
{
CacheObject valueFromCache = _cache.SingleOrDefault(u => u.UserId == userId);
// user was found
if (valueFromCache != null)
{
// if cache is outdated then remove value from it
if (valueFromCache.CreationDate.AddSeconds(_cacheDuration) < DateTime.Now)
{
// Upgrade to a write lock, as an item has to be removed from the cache.
// We will only enter the write lock if nobody holds either a read or write lock
_cacheLock.EnterWriteLock();
try
{
_cache.Remove(valueFromCache);
}
finally
{
_cacheLock.ExitWriteLock();
}
addToCache = true;
}
else
{
// update cache date
valueFromCache.CreationDate = DateTime.Now;
return valueFromCache.User;
}
}
// user is absent in cache
else
{
addToCache = true;
}
if (addToCache)
{
User result = _userRepository.GetUser(userId);
// Upgrade to a write lock, as an item will (probably) be added to the cache.
// We will only enter the write lock if nobody holds either a read or write lock
_cacheLock.EnterWriteLock();
try
{
if (_cache.Any(u => u.UserId != userId))
{
_cache.Add(new CacheObject() {User = result, UserId = userId, CreationDate = DateTime.Now});
}
}
finally
{
_cacheLock.ExitWriteLock();
}
return result;
}
}
finally
{
_cacheLock.ExitUpgradeableReadLock();
}
return null;
}
}
有了这个,多个线程将能够同时读取缓存,但如果必须写入,它将被锁定。
免责声明:我没有运行代码来检查它;)