从异步请求返回缓存条目时锁定

本文关键字:锁定 缓存 异步 请求 返回 | 更新日期: 2023-09-27 18:35:24

我写了一个应该从Web服务获取一些信息的方法。我想避免对服务的额外调用,所以我试图根据这篇文章将信息放在 MemoryCache 中。

不同之处在于我在客户端没有"SomeHeavyAndExpensiveComputing",但我将工作委托给Web服务。所以我想等待电话。

据我了解,在

当前的实现中,我可能会向 Web 服务器发出多个请求,因为我无法等待锁内的请求,这就是它移出锁的原因。

有没有更好的解决方案?

谢谢。

 private static readonly object CompanyInfoLock = new object(); 
 public async Task<CompanyDto> GetCompanyInfo()
                {
                    const string cacheKey = "_COMPANYINFO_";
                    CompanyDto companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
                    if (companyInfo != null) return companyInfo;
                    CompanyDto company = await _userManagementService.InvokeAsync(x => x.GetCompanyAsync(AppPrincipal.Current.CurrentCompanyId));
                    lock (CompanyInfoLock)
                    {
                        companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
                        if (companyInfo != null) return companyInfo;
                        MemoryCache.Default.Add(cacheKey, company, new CacheItemPolicy
                        {
                            SlidingExpiration = new TimeSpan(2, 0, 0)
                        });
                    }
                    return company;
                }

从异步请求返回缓存条目时锁定

使用SemaphoreSlim,以便在调用 Web 服务之前异步锁定并放置锁定块。

private static readonly SemaphoreSlim CompanyInfoLock = new SemaphoreSlim (1); 
public async Task<CompanyDto> GetCompanyInfo()
{
    const string cacheKey = "_COMPANYINFO_";
    CompanyDto companyInfo;
    companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
    if (companyInfo != null) return companyInfo;
    await CompanyInfoLock.WaitAsync();
    try
    {
        //Check a 2nd time inside the lock to see if the cache has the data.
        companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
        if (companyInfo != null) return companyInfo;
        companyInfo = await _userManagementService.InvokeAsync(x => x.GetCompanyAsync(AppPrincipal.Current.CurrentCompanyId));
        MemoryCache.Default.Add(cacheKey, companyInfo, new CacheItemPolicy
        {
            SlidingExpiration = new TimeSpan(2, 0, 0)
        });
        return companyInfo;
    }
    finally
    {
        CompanyInfoLock.Release();
    }
}