C# 如何使缓存存储库线程安全
我有以下带有缓存的存储库C# 如何使缓存存储库线程安全,c#,.net,multithreading,repository-pattern,C#,.net,Multithreading,Repository Pattern,我有以下带有缓存的存储库 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
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;
}
}
公共类用户
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串LastName{get;set;}
公共日期时间出生日期{get;set;}
}
公共接口存储库
{
用户GetUser(int userId);
}
公共类缓存对象
{
public int UserId{get;set;}
公共用户{get;set;}
公共日期时间创建日期{get;set;}
}
公共类CachedUserRepository:IUserRepository
{
专用IUserRepository\u用户存储库;
私有列表_cache=新列表();
私有int_cacheDuration=60;
公共缓存存储库(IUserRepository userRepository)
{
_userRepository=userRepository;
}
公共用户GetUser(int userId)
{
bool addToCache=false;
CacheObject valueFromCache=\u cache.SingleOrDefault(u=>u.UserId==UserId);
//找到了一个用户
if(valueFromCache!=null)
{
//如果缓存过期,则从中删除值
if(valueFromCache.CreationDate.AddSeconds(_cacheDuration)
我想在不同的线程中运行方法GetUser(),所以我需要使这个方法是线程安全的我该怎么做?
我没有看到任何优雅的解决方案,只锁定(someObject)到整个方法体。但结果是,我将无法获得任何性能提升我们通常使用以下方法:
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;
}
}
公共类CachedUserRepository:IUserRepository
{
private ReaderOnly ReaderWriterLockSlim\u cacheLock=new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
专用IUserRepository\u用户存储库;
私有列表_cache=新列表();
私有int_cacheDuration=60;
公共缓存存储库(IUserRepository userRepository)
{
_userRepository=userRepository;
}
公共用户GetUser(int userId)
{
bool addToCache=false;
//输入可升级的读锁,因为如果必须更新缓存,可能必须使用写锁
//多个线程可以同时读取缓存
_cacheLock.EnterUpgradeableReadLock();
尝试
{
CacheObject valueFromCache=\u cache.SingleOrDefault(u=>u.UserId==UserId);
//找到了一个用户
if(valueFromCache!=null)
{
//如果缓存过期,则从中删除值
if(valueFromCache.CreationDate.AddSeconds(_cacheDuration)u.UserId!=UserId))
{
_Add(new CacheObject(){User=result,UserId=UserId,CreationDate=DateTime.Now});
}
}
最后
{
_cacheLock.ExitWriteLock();
}
返回结果;
}
}
最后
{
_cacheLock.ExitUpgradeableReadLock();
}
返回null;
}
}
这样,多个线程将能够同时读取缓存,但如果必须写入缓存,它将被锁定
免责声明:我没有运行代码来检查;) 我们通常用这样的方法来做:
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;
}
}
公共类CachedUserRepository:IUserRepository
{
private ReaderOnly ReaderWriterLockSlim\u cacheLock=new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
专用IUserRepository\u用户存储库;
私有列表_cache=新列表();
私有int_cacheDuration=60;
公共缓存存储库(IUserRepository userRepository)
{
_userRepository=userRepository;
}
公共用户GetUser(int userId)
{
bool addToCache=false;
//输入可升级的读锁,因为如果必须更新缓存,可能必须使用写锁
//多个线程可以同时读取缓存
_cacheLock.EnterUpgradeableReadLock()