高性能缓存

以下代码应该缓存上次读取。 LastValueCache是一个可以被许multithreading访问的缓存(这就是我使用共享内存的原因)。 我可以有竞争条件,但我希望其他线程会看到更改的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); } } 

许multithreading都使用Repository对象。 我不想使用锁定,因为它会影响性能,在我的情况下,这比数据一致性更重要。 问题是哪种最小的同步机制能够满足我的需求? 也许在getset volatile或单个MemoryBarrier就足够了?

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

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

您担心内存毫秒,但在更新缓存之前,您正在等待对数据库的写入。
基于公共物品获取标记是一个关键。

让我们假设db写入是20毫秒
db读数为10 ms
缓存获取和缓存集均为2 ms

public void Save(Item item)
SaveToDatabase(项目); 20毫秒
Item cached = LastValueCache; 2毫秒
if(cached == null || item.Stamp> cached.Stamp)1 ms
LastValueCache = item; 2毫秒

在LastValueCache =项目之前的23毫秒内; 任何对公共项目Get(Timestamp戳记)的调用都将打到DataBase而不是缓存。

在LastValueCache = item之前的23 ms内; 任何对public Item LastValueCache get的调用都将获得一个过时23 ms的失效值。 所述目标是让其他线程看到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戳记)
数据库是您需要优化的调用
你需要再次剖析

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

volatile应该足够和最适合您的情况。 有些情况下单独使用volatile不足以确保读取获得最新值,但在这种情况下,我认为这不是一个重要因素。 有关详细信息,请参阅Joe Albahari撰写的这篇精彩文章的“volatile keyword”部分。

替代使用可能是ReaderWriterLockSlim类,以便为像您这样的读取器/写入器方案启用线程同步。

  ReaderWriterLockSlim _rw = new ReaderWriterLockSlim(); get { _rw.EnterReadLock(); SomeType result = field; _rw.ExitReadLock(); return result; } set { _rw.EnterWriteLock(); field = value; _rw.ExitWriteLock(); } 

这是Reader / Writer同步的有效实现。 Eric Lippert的博客文章可能会让您感兴趣。

另一个有趣的选项可能是ConcurrentExclusiveSchedulerPair类,它为任务创建两个TaskScheduler,可以在“具有读访问权限的任务”(并发)和“具有写访问权限的任务”(独占)中进行拆分。

有关这方面的更多信息,请点击此处