我们使用一个简单的Memory Cache来缓存密集查询的响应,否则每秒会被多次访问。缓存非常快,偏移量设置为2秒。
public StateService
{
private readonly ObjectCache _cache = MemoryCache.Default;
private const string _queueStatesCacheKey = "_states";
public IList<States> GetStates()
{
var states = _cache.Get(_statesCacheKey);
if (states== null)
{
states = getStatesFromDatabase();
_cache.Set(_statesCacheKey, states, DateTimeOffset.Now.AddSeconds(Settings.AppSettings.QueueStateCacheExpiration));
}
return states as List<States>;
}
}方法:getStatesFromDatabase()只运行一个SQL-query来运行存储过程并获取这些值。
所有这些都是通过API获取的,目前,如果缓存被清除并且getStatesFromDatabase()同时被4-5个线程击中,我们正在经历这样的情况。
GetStates()包装在Task中,然后等待它完成,以等待另一个请求启动一个新任务?List<States>的新的提供程序?发布于 2020-02-28 13:47:13
使用SemaphoreSlim锁定其他线程,直到缓存就绪:
public StateService
{
private readonly ObjectCache _cache = MemoryCache.Default;
private const string _queueStatesCacheKey = "_states";
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
public IList<States> GetStates()
{
var states = _cache.Get(_statesCacheKey);
if (states== null)
{
try
{
semaphore.Wait();
// we check again from cache, that could have been populated from other thread
states = _cache.Get(_statesCacheKey);
if(states != null) return states as IList<States>;
states = getStatesFromDatabase();
_cache.Set(_statesCacheKey, states, DateTimeOffset.Now.AddSeconds(Settings.AppSettings.QueueStateCacheExpiration));
}
finally
{
semaphore.Release();
}
}
return states as List<States>;
}
}您可以配置没有超时(如示例中的)或某种类型的超时,可能基于查询的运行时间统计信息。
请注意,这将只在一台服务器&单一进程设置中工作。如果您的应用程序要在多个服务器或多个进程上运行,则此解决方案将允许每个服务器/进程执行一个并发查询。
为了避免这种情况,您需要检查一些用于外部管理锁的包(分布式锁定)。例如,Nuget DistributedLock就是这样做的。
发布于 2020-02-28 13:50:41
将GetStates()封装在Task中并等待它不会修复任何问题,因为您正在使用asp.net应用程序--每个用户请求都是在新Thread中接收的。在返回数据之前,一个请求等待另一个请求获取某物,这不是一个好主意。当我看到实现您的方法时,您将不得不在一些Singleton中锁定方法或维护已经在运行的任务列表,您将不得不担心线程安全、任务取消等等。它会使事情复杂化而不是解决问题。
如果您的GetStates()不经常被调用,那么您拥有的实际上是很好的实现。另一种解决方案是在内存中维护list,始终返回该列表并通过每x秒轮询数据库更新它。这样,不管有多少用户来,总是只有一个线程从数据库中检索数据。
基本上,如果您的情况是没有人查询您的服务一段时间,那么您的方法是好的,如果您的服务足够繁忙,每x秒轮询和总是返回列表会更好。
https://stackoverflow.com/questions/60452826
复制相似问题