首先,我无法使标题更具解释性,我将尝试列出问题,然后为其提供解决方案
我正在为我们的游戏在asp核心中实现一个后端,我们收到的请求有些大,比如请求商店中提供的物品,每个用户启动游戏都会加载商店信息,从而使数据库之旅提取几乎很少变化的整个商店信息-每月少于一次-因此我们正在进行数千次不需要的数据库旅行。
最重要的是,我们返回时间戳,表示商品图像的最后一次更改时间,图像存储在blob中,这使我可以查询blob的更改日期,从而使请求的方式更加昂贵
因此,为了解决所有这些问题,我实现了一个小类来缓存请求,直到需要针对该请求和其他请求进行更新为止,但是我不确定我是否正确地查看了该请求
这是基本的抽象类:
public abstract class CachedModel<T>
{
protected T Model { get; set; }
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1,1);
protected abstract Task ThreadSafeUpdateAsync();
protected abstract bool NeedsUpdate();
public async Task<T> GetModel()
{
if (NeedsUpdate())
{
try
{
await semaphore.WaitAsync();
if(NeedsUpdate()) // not sure if this is needed, can other threads enter here after the first one already updated the object?
await ThreadSafeUpdateAsync();
}
finally
{
semaphore.Release();
}
}
return Model;
}
}
然后我按照每个请求实现此类:
public class CachedStoreInfo : CachedModel<DesiredModel>
{
protected override async Task ThreadSafeUpdateAsync()
{
// make the trip to db and Blob service
Model = some result
}
protected override bool NeedsUpdate()
{
return someLogicToDecideIfNeedsUpdate;
}
}
最后,在asp控制器中,我所需要做的就是:
[HttpGet]
public async Task<DesiredModel> GetStoreInfo()
{
return await cachedStoreInfo.GetModel();
}
这是正确的实现吗?甚至有必要这样做还是有一种更聪明的方法来实现这一目标?从blob获取时间戳是我虽然要缓存结果的主要原因
答案 0 :(得分:0)
您的实现看起来正确。当然,CachedStoreInfo
的实例在所需范围内应为单例(据我所知,在应用程序范围内应为单例)。
第一个已经更新对象后,其他线程可以进入这里吗?
正如Kevin Gosse指出的,其他线程可以在此处输入。 NeedsUpdate()
的第二张支票是Double-checked locking模式的一部分。这可能是一个很好的优化。
这甚至是必要的还是有一种更聪明的方法来实现这一目标?
对于我来说,您的实现非常简单,足够聪明