0

请向我建议一种模式来执行以下多线程任务:

我要缓存表行,需要通过两种方式找到它们:

  • 按 ID(整数)
  • 按键(字符串)

我想要单行存储,并使用两个字典来有效地查找行。

在缓存中,我必须从 db 中读取每一行并将其存储在全局存储中,并通过 key 和 id 将其添加到两个字典中。我需要所有这些东西都必须在多线程环境中工作。

谁能建议一种优雅的方式来做到这一点?

更新。我的错。我错过了试图避免锁的明显(对我自己)限制,因为在更“常见”用法的情况下,当从某个不同的源(不是数据库)读取行时,锁可能会导致死锁......

4

2 回答 2

3

这几乎是处理原子操作的经典案例。使用您的方法将项目添加到缓存涉及至少三个需要原子执行的操作:从 db 检索数据,将其存储在 dictionaryByKey 中,将其存储在 dictionaryByName 中。

ConcurrentDictionary 在这里对您没有帮助,因为该对象只能保护自己免受并发请求的影响——因为它不知道还有其他操作需要以原子方式发生,所以它无法帮助您避免一致性问题。

基本解决方案很简单:使用 rwlock 保护对缓存的读取和写入。ReaderWriterLock(Slim) 应该可以正常工作,特别是因为我假设大多数缓存命中都有望被读取。

假设 MyCache 是您的缓存类,获取项目将如下所示:

public class MyCache{
   private ReaderWriterLock rwlock;

.....................

public object Get(int id)//same for the other one based on name
{
   rwlock.AcquireReaderLock(Timeout.Infinite);
   try{
      if(cacheID.Contains(id)){return cacheID[id];}

      //item MIGHT not be in cache (not certain since we're still under read lock)
      //1. fetch from db BEFORE upgrade to write - avoid blocking all other readers
      var item = GetItemFromStorage(id);//you get the idea

      LockCookie lk = rwlock.UpgradeToWriterLock(Timeout.Infinite);
      try{
          if(cacheID.Contains(id)){return cacheID[id];}//check again!!!

          //2. insert in cacheID
          cacheID[id]=item;
          //3. insert in cacheName
          cacheName[item->key]=item;
          //return value  
          return item;

      }finally{rwlock.DowngradeFromWriterLock(ref lk);}
   }
   finally{rwlock.ExitReadLock();}
}
于 2013-10-09T12:26:08.160 回答
0
private object dictLock = new object();
private Dictionary<int, int> dict1 = new Dictionary<int, int>();
private Dictionary<string, int> dict2 = new Dictionary<string, int>();

public void Add(int rownr, int id, string key)
{
    lock(dictLock)
    {
        dict1.Add(id, rownr);
        dict2.Add(key, rownr);
    }
}

public int GetRow(int id)
{
    lock(dictLock)
    {
        return dict1[id];
    }
}

public int GetRow(string key)
{
    lock(dictLock)
    {
        return dict2[key];
    }
}
于 2013-10-09T12:11:10.397 回答