Tom*_*len 5 c# asp.net search thread-safety
当用户输入query以搜索:
如果用户执行的搜索时间为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];
}
Run Code Online (Sandbox Code Playgroud)
你的并发使用ManualSearchLocks是不安全的,ConcurrentDictionary是一个很好的替代品。不,仅仅阅读字典并不安全,因为没有记录表明它是安全的。
我会把一个放入Lazy<T>缓存中。可能会产生多个此类惰性实例,但只有一个会被具体化。所有想要访问特定键的线程都会调用Lazy.Value并自动同步。一旦执行一次实际的“搜索”。
根据您访问缓存的方式,可能会存在一个小的竞争条件,允许执行多个惰性实例。对于你的情况来说,这可能不是什么大问题。