c# - 高性能缓存

标签 c# .net multithreading

下面的代码应该缓存最后一次读取。 LastValueCache 是一个可以被多个线程访问的缓存(这就是我使用共享内存的原因)。有竞争条件对我来说没问题,但我希望其他线程能看到更改后的 LastValueCache

class Repository
{
    public Item LastValueCache
    {
        get
        {
            Thread.MemoryBarrier();
            SomeType result = field;
            Thread.MemoryBarrier();
            return result;
        }
        set
        {
            Thread.MemoryBarrier();
            field = value;
            Thread.MemoryBarrier();
        }
    }

    public void Save(Item item)
    {
        SaveToDatabase(item);
        Item cached = LastValueCache;
        if (cached == null || item.Stamp > cached.Stamp)
        {
            LastValueCache = item;
        }
    }

    public void Remove(Timestamp stamp)
    {
        RemoveFromDatabase(item);
        Item cached = LastValueCache;
        if (cached != null && cached.Stamp == item.Stamp)
        {
            LastValueCache = null;
        }
    }

    public Item Get(Timestamp stamp)
    {
        Item cached = LastValueCache;
        if (cached != null && cached.Stamp == stamp)
        {
            return cached;
        }

        return GetFromDatabase(stamp);
    }
}

Repository 对象被许多线程使用。我不想使用锁定,因为它会影响性能,在我的例子中,性能比数据一致性更重要。问题是什么最小的同步机制能满足我的需要?可能是 volatileget 中的单个 MemoryBarrierset 就够了吗?

最佳答案

如果这是愚蠢的,你不需要投票给我。
告诉我,我会删除。
但我不遵循这个逻辑。

public void Save(Item item)
{
    SaveToDatabase(item);
    Item cached = LastValueCache;
    if (cached == null || item.Stamp > cached.Stamp)
    {
        LastValueCache = item;
    }
}

您担心内存毫秒,但在更新缓存之前您正在等待写入数据库。
基于public Item Get stamp是一个key。

让我们假设一个数据库写入是 20 毫秒
一个数据库读取是 10 毫秒
Cache get和cache set各2ms

public void Save(Item item)
保存到数据库(项目); 20 毫秒
项目缓存 = LastValueCache; 2 毫秒
如果(缓存 == null || item.Stamp > cached.Stamp)1 毫秒
LastValueCache = 项目; 2毫秒

在 LastValueCache = item 之前的 23 毫秒内;对 public Item Get(Timestamp stamp) 的任何调用都将命中数据库而不是缓存。

在 LastValueCache = item 之前的 23 毫秒内;对 public Item LastValueCache 的任何调用 get 将获得一个过时 23 毫秒的值。 声明的目标是让其他线程看到 LastValueCache - 但看到的是陈旧的 LastValueCache。

与删除相同。
您将多次访问本可以避免的数据库。

你想达到什么目的?
你有没有介绍过这个?

我敢打赌瓶颈是对数据库的调用。
数据库调用比锁和 MemoryBarrier 之间的差异长 1000 倍。

public void Save(Item item)
{   
   // add logic that the prior asynchonous call to SaveToDatabase is complete
   // if not wait for it to complete 
   // LastValueCache will possible be replaced so you need last item in the database 
   // the time for a lock is not really a factor as it will be faster than the prior update 
   Item cached = LastValueCache;
   if (cached == null || item.Stamp > cached.Stamp)
   {
       LastValueCache = item;
   }
   // make the next a task or background so it does not block    
   SaveToDatabase(item);
}

如果您设置 LastValueCache = item,甚至可以将逻辑更改为仅等待之前的调用;
但是你需要以某种方式限制数据库

下一步是缓存最后一个 X 并在 Item Get(Timestamp stamp) 中使用它
数据库调用是你需要优化的
同样,您需要分析

之后逻辑会变得更加复杂,但会将数据库调用提供给 BlockingCollection。需要确保最后一个 X 缓存大于 BlockingCollections 大小。如果不阻塞,等待 BC 清除。并且您需要使用相同的 BC 进行插入和删除,以便按顺序处理它们。可以变得足够聪明,以至于您只是不插入具有删除的记录。并且不要一次只插入或删除一条记录。

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

相关文章:

javascript - 如何将 JavaScript 变量传递给服务器端方法

c# - 只返回 View 的 Controller Action 是否有必要异步?

java - 单例模式的正确使用

C# 多接口(interface)继承不允许具有相同名称的公共(public)访问修饰符

c# - 在 C# 中显示打印预览

.net - WCF 和 NetTcp 绑定(bind)

multithreading - Perl 或 Bash 线程池脚本?

java - Android中两个并发的AsyncTasks-如何处理竞争条件?

c# - 如何将 newtonsoft 转换为驼峰式对象属性

c# - 使用 ASP.NET Core OData 8.0 映射动态 odata 路由