gpt4 book ai didi

c# - 异步/等待和缓存

转载 作者:可可西里 更新时间:2023-11-01 08:04:43 25 4
gpt4 key购买 nike

我的服务层正在将大量 Db 请求缓存到 memcached,这是否导致无法使用 Async/Await??例如,我怎么能等待这个?

public virtual Store GetStoreByUsername(string username)
{
return _cacheManager.Get(string.Format("Cache_Key_{0}", username), () =>
{
return _storeRepository.GetSingle(x => x.UserName == username);
});
}

注意:如果缓存中存在键,它将返回一个“Store”(不是 Task<Store> ),如果缓存中不存在键,它将执行 lambda。如果我将 Func 更改为

return await _storeRepository.GetSingleAsync(x => x.UserName == username);

方法签名为

public virtual async Task<Store> GetStoreByUsername(string username)

由于缓存返回类型,这显然行不通。

最佳答案

这是一种缓存异步操作结果的方法,可以保证没有缓存未命中并且是线程安全的。

在已接受的答案中,如果在一个循环中或从多个线程多次请求相同的用户名,数据库请求将不断发送,直到有一个响应被缓存,此时缓存将开始被使用。

下面的方法创建一个 SemaphoreSlim每个唯一键的对象。这将防止长时间运行的 async 操作针对同一键运行多次,同时允许它针对不同的键同时运行。显然,保留 SemaphoreSlim 对象以防止缓存未命中会产生开销,因此根据用例的不同,这样做可能不值得。但是,如果保证没有缓存未命中很重要,那么这就可以做到这一点。

private readonly ConcurrentDictionary<string, SemaphoreSlim> _keyLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
private readonly ConcurrentDictionary<string, Store> _cache = new ConcurrentDictionary<string, Store>();

public async Task<Store> GetStoreByUsernameAsync(string username)
{
Store value;
// get the semaphore specific to this username
var keyLock = _keyLocks.GetOrAdd(username, x => new SemaphoreSlim(1));
await keyLock.WaitAsync().ConfigureAwait(false);
try
{
// try to get Store from cache
if (!_cache.TryGetValue(username, out value))
{
// if value isn't cached, get it from the DB asynchronously
value = await _storeRepository.GetSingleAsync(x => x.UserName == username).ConfigureAwait(false);

// cache value
_cache.TryAdd(username, value);
}
}
finally
{
keyLock.Release();
}
return value;
}

注意:为了进一步优化此方法,可以在锁定获取步骤之前执行额外的缓存检查。

关于c# - 异步/等待和缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22829844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com