c# - 实现搜索结果的线程安全缓存

标签 c# asp.net search thread-safety

搜索结果缓存的工作原理

当用户输入query来搜索时:

  • 查询被拆分为一个标记数组
  • 为这个 token 数组创建一个唯一的散列(按字母顺序排列 token ,然后是 MD5)。这是搜索的唯一标识。
  • 根据哈希检查缓存中的结果
  • 如果缓存不存在,使用哈希将结果保存到缓存

我要解决的问题

如果用户执行搜索需要 10 秒,并且他们不耐烦地刷新页面,我们不希望它再次开始查询。这应该被锁定。

但是,如果正在运行代价高昂的查询,我们不想阻止其他用户执行代价较低的搜索。

为了解决这个问题,我需要多把锁。

实现

这就是我目前实现它的方式:

private static readonly object MasterManualSearchLock = new object();
private static readonly Dictionary<string, object> ManualSearchLocks = new Dictionary<string, object>();

/// <summary>
/// Search the manual
/// </summary>
public static SearchResponse DoSearch(string query, Manual forManual)
{
    var tokens = Search.Functions.TokeniseSearchQuery(query);
    var tokenHash = Search.Functions.GetUniqueHashOfTokens(tokens);
    var cacheIndex = Settings.CachePrefix + "SavedManualSearch_" + tokenHash;
    var context = HttpContext.Current;

    if (context.Cache[cacheIndex] == null)
    {
        // Create lock if it doesn't exist
        if (!ManualSearchLocks.ContainsKey(tokenHash))
        {
            lock (MasterManualSearchLock)
            {
                if (!ManualSearchLocks.ContainsKey(tokenHash))
                {
                    ManualSearchLocks.Add(tokenHash, new object());
                }
            }

        }

        lock (ManualSearchLocks[tokenHash])
        {
            if (context.Cache[cacheIndex] == null)
            {
                var searchResponse = new SearchResponse(tokens, forManual, query);
                context.Cache.Add(cacheIndex, searchResponse, null, DateTime.Now.AddMinutes(Settings.Search.SearchResultsAbsoluteTimeoutMins), Cache.NoSlidingExpiration, CacheItemPriority.BelowNormal, null);
            }
            ManualSearchLocks.Remove(tokenHash);
        }

    }
    return (SearchResponse)context.Cache[cacheIndex];
} 

问题

  • 这是一个明智的实现吗?
  • 这个线程安全吗?
  • 在锁本身内包括解除锁是否可行?

最佳答案

您同时使用 ManualSearchLocks不安全,ConcurrentDictionary是一个很好的替代品。不,仅仅从字典中阅读是不安全的,因为它没有被证明是安全的。

我会放一个 Lazy<T>进入缓存。可能会产生多个这样的惰性实例,但只会具体化一个。所有想要访问特定 key 的线程都将调用 Lazy.Value并自动同步。一旦执行一次实际的“搜索”。

根据您访问缓存的方式,可能存在允许执行多个惰性实例的小型竞争条件。这对您来说可能不是什么大问题。

关于c# - 实现搜索结果的线程安全缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32382155/

相关文章:

c# - 匿名实例化语法——好还是坏?

c# - 有没有办法从 app.config 文件加载 Linq to SQL 的现有连接字符串?

asp.net - 如何自定义网站项目的构建?

c# - HttpRuntime.Cache 没有过期?

xml - 当节点包含特殊字符时使用 Xquery 处理 XML 标题搜索的最佳方法

windows - 搜索具有特定文件内容的文件

c# - 将文件从 silverlight 上传到 WCF 服务

c# - ListBox SelectedValueChanged/SelectedIndexChanged 在数据源更改时不触发

javascript - 如何以编程方式将图片上传到 Facebook?

python - 如何交换从列表 .txt 文件中读取的数字?错误 "list index out of range"