首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >访问数据库的多个请求--等待缓存可用

访问数据库的多个请求--等待缓存可用
EN

Stack Overflow用户
提问于 2020-02-28 13:32:37
回答 2查看 808关注 0票数 0

我们使用一个简单的Memory Cache来缓存密集查询的响应,否则每秒会被多次访问。缓存非常快,偏移量设置为2秒。

代码语言:javascript
复制
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>的新的提供程序?
  • 最好是以不同的方式来缓存它,还是在其他地方缓存呢?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-02-28 13:47:13

使用SemaphoreSlim锁定其他线程,直到缓存就绪:

代码语言:javascript
复制
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就是这样做的。

票数 2
EN

Stack Overflow用户

发布于 2020-02-28 13:50:41

GetStates()封装在Task中并等待它不会修复任何问题,因为您正在使用asp.net应用程序--每个用户请求都是在新Thread中接收的。在返回数据之前,一个请求等待另一个请求获取某物,这不是一个好主意。当我看到实现您的方法时,您将不得不在一些Singleton中锁定方法或维护已经在运行的任务列表,您将不得不担心线程安全、任务取消等等。它会使事情复杂化而不是解决问题。

如果您的GetStates()不经常被调用,那么您拥有的实际上是很好的实现。另一种解决方案是在内存中维护list,始终返回该列表并通过每x秒轮询数据库更新它。这样,不管有多少用户来,总是只有一个线程从数据库中检索数据。

基本上,如果您的情况是没有人查询您的服务一段时间,那么您的方法是好的,如果您的服务足够繁忙,每x秒轮询和总是返回列表会更好。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60452826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档