首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >高性能缓存

高性能缓存
EN

Stack Overflow用户
提问于 2014-03-17 21:30:53
回答 4查看 1.3K关注 0票数 7

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

代码语言:javascript
复制
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对象被许多线程使用。我不想使用锁定,因为它会影响性能,在我的情况下,这比数据一致性更重要。问题是,,适合我需要的最小的同步机制是什么?,也许volatile,或者getset中的单一MemoryBarrier就足够了?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-03-18 00:25:10

如果这很蠢,你就不用投我一票。

告诉我我就删掉。

但我没有遵循这个逻辑。

代码语言:javascript
复制
public void Save(Item item)
{
    SaveToDatabase(item);
    Item cached = LastValueCache;
    if (cached == null || item.Stamp > cached.Stamp)
    {
        LastValueCache = item;
    }
}

您担心内存毫秒,但在更新缓存之前,您正在等待对数据库的写入。

基于公共物品的盖章是一个关键。

假设db写为20 ms。

db读为10 ms。

缓存获取和缓存集分别为2ms。

公众无效保存(项目)

SaveToDatabase(项目);20 ms

项缓存= LastValueCache;2ms

如果(缓存的== null _ item.Stamp > cached.Stamp) 1毫秒

LastValueCache =项目;2 ms

在LastValueCache = Item之前的23 ms期间,任何对公共项目Get(时间戳)的调用都会击中DataBase而不是缓存。

在LastValueCache = Item之前的23 ms期间,对公共项的任何调用都会得到一个过期的23 ms的值。声明的目标是让其他线程看到LastValueCache,但是看到的是一个陈旧的LastValueCache。

移除也是一样的。

您将有几次命中数据库,您本可以避免。

你想达到什么目的?

你描述过这个了吗?

我打赌瓶颈是对数据库的调用。

数据库调用比锁和MemoryBarrier之间的差异长1000倍。

代码语言:javascript
复制
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中使用它(时间戳)

数据库是您需要优化的调用

再一次,你需要分析

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

票数 3
EN

Stack Overflow用户

发布于 2020-06-17 05:44:32

我实现了一个为并发工作负载设计的线程安全伪LRU : ConcurrentLru。性能非常接近ConcurrentDictionary,比MemoryCache快10倍,命中率优于常规的LRU。在下面的github链接中提供了全面分析。

用法如下:

代码语言:javascript
复制
int capacity = 666;
var lru = new ConcurrentLru<int, SomeItem>(capacity);

var value = lru.GetOrAdd(1, (k) => new SomeItem(k));

GitHub:https://github.com/bitfaster/BitFaster.Caching

代码语言:javascript
复制
Install-Package BitFaster.Caching
票数 3
EN

Stack Overflow用户

发布于 2014-03-17 21:53:22

对于您的情况,volatile应该是足够的和最具表现力的。在一些潜在的情况下,仅靠volatile并不足以确保读到的内容得到最及时的值,但在这种情况下,我不认为它是一个重要的因素。有关详细信息,请参阅这篇由乔·阿尔巴哈里撰写的精彩文章的“易失性关键字”部分。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22465853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档