我有一个 ASP.NET MVC 2 Web 应用程序(.NET 4,C#),用户可以在其中搜索位置。
该页面使用自动完成框实现,类似于许多网站。 (谷歌、YouTube 等)
现在,对服务器的 AJAX 调用会导致对数据库的存储过程调用。 (虽然高效,但可能会导致打字慢的人往返很多次)。
我想知道如何创建一个策略来缓存最近 100 次搜索的结果?
我不能使用 OutputCache,因为调用是通过客户端的 AJAX 进行的。我需要缓存存储过程的输出(查询文本的匹配位置列表)。
换句话说,很多人会搜索“纽约”或“旧金山”,而这些数据只能通过手动管理员更改来更改(例如,我们可以手动使缓存无效)。
那么,我如何缓存最近 100 次搜索?我希望有一个类似 FIFO 的功能,如果缓存已经有 100 个搜索,最旧的搜索就会被丢弃,所有的都被向下移动。
我希望代码是这样的:
public ICollection<MatchedLocation> FindLocations(string queryText)
{
// Check last 100 searches.. How?
string cacheKey = queryText;
var matchedLocations = cachedPersistence.Get(cacheKey);
if (matchedLocations == null)
{
// Call db
matchedLocations = dbPersistence.GetLocations(queryText);
// Add to cache
cachedPersistence.Add(cacheKey, matchedLocations);
}
else
{
// Found in Cache! Awesome!
return matchedLocations;
}
}
我认为显而易见的选择是 .NET Queue ?
但我以前从未使用过它,所以有什么建议吗?我将如何为 get/set 实现并发,我需要使用完全锁定的 Singleton 吗?有没有人为此目的使用过队列?我们还有哪些其他选择?我几乎需要一个自定义队列来限制堆栈中的项目数。
感谢您的帮助。
最佳答案
如果您只想缓存 100,您可以使用带有上次使用时间的对应字典的字典。并且您可以使用读写器锁而不是允许多个读取器的完全成熟的锁。
使用下面的代码,两个线程可能会为相同的值输入 EnterWriteLock
。惩罚是两次数据库调用,这可能不是问题。您可以通过执行另一个 TryGetValue
并在必要时锁定(双重锁定)来避免这种情况。
class Cache
{
static readonly Dictionary<string, ICollection<MatchedLocation>> _cache = new Dictionary<string, ICollection<MatchedLocation>>(100);
static readonly Dictionary<string,DateTime> _cacheTimes = new Dictionary<string, DateTime>(100);
static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
public ICollection<MatchedLocation> FindLocations(string queryText)
{
_lock.EnterUpgradeableReadLock();
try
{
ICollection<MatchedLocation> result;
if (_cache.TryGetValue(queryText, out result))
{
return result;
}
else
{
_lock.EnterWriteLock();
try
{
// expire cache items
if( _cache.Count > 100)
{
// could be more efficient http://code.google.com/p/morelinq/ - MinBy
string key = _cacheTimes.OrderBy(item => item.Value).First().Key;
_cacheTimes.Remove(key);
_cache.Remove(key);
}
// add new item
result = dbPersistence.GetLocations(queryText);
_cache[queryText] = result;
_cacheTimes[queryText] = DateTime.UtcNow;
}
finally
{
_lock.ExitWriteLock();
}
return result;
}
}
finally
{
_lock.ExitUpgradeableReadLock();
}
}
}
关于c# - 缓存先前搜索的策略 (ASP.NET),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3976501/