c# - 高性能内存缓存的线程安全

标签 c# performance thread-safety micro-optimization

我有一个静态内存缓存,每小时(或更长时间)写入一次,并且以极高的速率被许多线程读取。传统观点建议我遵循如下模式:

public static class MyCache
{
    private static IDictionary<int, string> _cache;
    private static ReaderWriterLockSlim _sharedLock;

    static MyCache()
    {
        _cache = new Dictionary<int, string>();
        _sharedLock = new ReaderWriterLockSlim();
    }

    public static string GetData(int key)
    {
        _sharedLock.EnterReadLock();
        try
        {
            string returnValue;
            _cache.TryGetValue(key, out returnValue);
            return returnValue;
        }
        finally
        {
            _sharedLock.ExitReadLock();
        }
    }

    public static void AddData(int key, string data)
    {
        _sharedLock.EnterWriteLock();
        try
        {
            if (!_cache.ContainsKey(key))
                _cache.Add(key, data);
        }
        finally
        {
            _sharedLock.ExitWriteLock();
        }
    }
}

作为微优化练习,我怎样才能在共享锁的相对开销中削减更多的滴答? 写作 的时间可能很昂贵,因为它很少发生。我需要尽可能快地进行读取。在这种情况下,我可以只删除read 锁(如下)并保持线程安全吗?或者有没有我可以使用的无锁版本?我熟悉内存防护,但不知道如何在这种情况下安全地应用它。

注意:我不依赖于任何一种模式,所以欢迎任何建议,只要最终结果更快并且在 C# 4.x 中。*

public static class MyCache2
{
    private static IDictionary<int, string> _cache;
    private static object _fullLock;

    static MyCache2()
    {
        _cache = new Dictionary<int, string>();
        _fullLock = new object();
    }

    public static string GetData(int key)
    {
        //Note: There is no locking here... Is that ok?
        string returnValue;
        _cache.TryGetValue(key, out returnValue);
        return returnValue;
    }

    public static void AddData(int key, string data)
    {
        lock (_fullLock)
        {
            if (!_cache.ContainsKey(key))
                _cache.Add(key, data);
        }
    }
}

最佳答案

当线程只从数据结构中读取时,您不需要锁。因此,由于写入非常罕见(而且,我假设,不是并发的),一个选项可能是制作字典的完整副本,对副本进行修改,然后以原子方式将旧字典与新字典交换:

public static class MyCache2
{
    private static IDictionary<int, string> _cache;

    static MyCache2()
    {
        _cache = new Dictionary<int, string>();
    }

    public static string GetData(int key)
    {
        string returnValue;
        _cache.TryGetValue(key, out returnValue);
        return returnValue;
    }

    public static void AddData(int key, string data)
    {
        IDictionary<int, string> clone = Clone(_cache);
        if (!clone.ContainsKey(key))
            clone.Add(key, data);
        Interlocked.Exchange(ref _cache, clone);
    }
}

关于c# - 高性能内存缓存的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8195320/

相关文章:

c# - _MailAutoSig 书签丢失(Outlook 2010)

php - 检查表中是否存在值或处理MySQL的唯一约束异常?

c# - 区分本质上是Int32的多种类型

C#|线程执行后程序不执行任何操作

multithreading - 在 Spring 可以安全地在请求线程内生成新线程

c# - 交换对象和线程安全性有任何问题吗?

c# - 使用 R 对 DocumentDB 资源进行访问控制

c# - 使用可选参数初始化 WPF 窗口

c# - 如何使用 LINQ 对集合中的每个字符串调用 ToLower()?

Java - 我应该在哪里初始化变量以提高内存效率?