下面的代码应该缓存最后一次读取。 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
对象被许多线程使用。我不想使用锁定,因为它会影响性能,在我的例子中,性能比数据一致性更重要。问题是什么最小的同步机制能满足我的需要?可能是 volatile
或 get
中的单个 MemoryBarrier
和 set
就够了吗?
最佳答案
如果这是愚蠢的,你不需要投票给我。
告诉我,我会删除。
但我不遵循这个逻辑。
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/