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()