Skip to main content
 首页 » 编程设计

c#之寻找一种在缓存时减少锁定的方法

2024年01月13日32qq78292959

我正在使用下面的代码来缓存项目。这是非常基本的。

我遇到的问题是,每次它缓存一个项目时,代码部分都会锁定。因此,每小时大约有一百万件元素到达,这是一个问题。

我已经尝试为每个 cacheKey 创建一个静态锁对象的字典,这样锁定是细粒度的,但这本身就成为管理它们过期等的问题......

有没有更好的方法来实现最小锁定?

private static readonly object cacheLock = new object(); 
public static T GetFromCache<T>(string cacheKey, 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 retrieval. 
    T cachedData = MemoryCache.Default.Get(cacheKey) 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) as T; 
 
        if (cachedData != null) { 
            return cachedData; 
        } 
 
        // The value still did not exist so we now write it in to the cache. 
        cachedData = GetData(); 
 
        MemoryCache.Default.Set(cacheKey, cachedData, new CacheItemPolicy(...)); 
        return cachedData; 
    } 
} 

请您参考如下方法:

您可能需要考虑使用 ReaderWriterLockSlim ,只有在需要的时候才能获得写锁。

使用 cacheLock.EnterReadLock(); 和 cacheLock.EnterWriteLock(); 应该会大大提高性能。

我给的那个链接甚至有一个缓存的例子,正是你需要的,我复制在这里:

public class SynchronizedCache  
{ 
    private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(); 
    private Dictionary<int, string> innerCache = new Dictionary<int, string>(); 
 
    public int Count 
    { get { return innerCache.Count; } } 
 
    public string Read(int key) 
    { 
        cacheLock.EnterReadLock(); 
        try 
        { 
            return innerCache[key]; 
        } 
        finally 
        { 
            cacheLock.ExitReadLock(); 
        } 
    } 
 
    public void Add(int key, string value) 
    { 
        cacheLock.EnterWriteLock(); 
        try 
        { 
            innerCache.Add(key, value); 
        } 
        finally 
        { 
            cacheLock.ExitWriteLock(); 
        } 
    } 
 
    public bool AddWithTimeout(int key, string value, int timeout) 
    { 
        if (cacheLock.TryEnterWriteLock(timeout)) 
        { 
            try 
            { 
                innerCache.Add(key, value); 
            } 
            finally 
            { 
                cacheLock.ExitWriteLock(); 
            } 
            return true; 
        } 
        else 
        { 
            return false; 
        } 
    } 
 
    public AddOrUpdateStatus AddOrUpdate(int key, string value) 
    { 
        cacheLock.EnterUpgradeableReadLock(); 
        try 
        { 
            string result = null; 
            if (innerCache.TryGetValue(key, out result)) 
            { 
                if (result == value) 
                { 
                    return AddOrUpdateStatus.Unchanged; 
                } 
                else 
                { 
                    cacheLock.EnterWriteLock(); 
                    try 
                    { 
                        innerCache[key] = value; 
                    } 
                    finally 
                    { 
                        cacheLock.ExitWriteLock(); 
                    } 
                    return AddOrUpdateStatus.Updated; 
                } 
            } 
            else 
            { 
                cacheLock.EnterWriteLock(); 
                try 
                { 
                    innerCache.Add(key, value); 
                } 
                finally 
                { 
                    cacheLock.ExitWriteLock(); 
                } 
                return AddOrUpdateStatus.Added; 
            } 
        } 
        finally 
        { 
            cacheLock.ExitUpgradeableReadLock(); 
        } 
    } 
 
    public void Delete(int key) 
    { 
        cacheLock.EnterWriteLock(); 
        try 
        { 
            innerCache.Remove(key); 
        } 
        finally 
        { 
            cacheLock.ExitWriteLock(); 
        } 
    } 
 
    public enum AddOrUpdateStatus 
    { 
        Added, 
        Updated, 
        Unchanged 
    }; 
 
    ~SynchronizedCache() 
    { 
       if (cacheLock != null) cacheLock.Dispose(); 
    } 
}