高性能缓存

Pel*_*red 5 .net c# 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

该Repository对象被许多线程使用.我不想使用锁定,因为它会影响性能,在我的情况下,这比数据一致性更重要.问题是哪种最小的同步机制能够满足我的需求?也许volatile或单MemoryBarrier中get和set就足够了?

pap*_*zzo 3

如果这很愚蠢,你不需要投票反对我。
只要告诉我,我就会删除。
但我不遵循这个逻辑。

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

您担心内存毫秒数,但在更新缓存之前正在等待写入数据库。
基于公共Item获取印章是关键。

假设数据库写入为 20 毫秒
数据库读取为 10 毫秒
缓存获取和缓存设置各为 2 毫秒

公共无效保存(项目项目)
SaveToDatabase(项目);20 毫秒
项目缓存 = LastValueCache; 2 毫秒
if (cached == null || item.Stamp > cached.Stamp) 1 毫秒
LastValueCache = item; 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 我会考虑异步执行数据库更新。并且不只是缓存最后一个 then 缓存,然后使用并发集合来保存最后一个 x。数据库是你的瓶颈。我会发布一个示例,但甚至没有得到+1。 (2认同)