

新闻资讯
技术学院MemoryCache.GetOrCreateAsync是最简安全路径,其内置并发协调机制确保同一key的factory只执行一次;应避免手动加锁、慎用Set而改用Refresh,key需纯函数式构造,淘汰回调须幂等。
MemoryCache 配合 GetOrCreateAsync 是最简安全路径高并发下直接读写缓存(比如先 TryGetValue 再 Set)必然引发重复计算和缓存击穿。.NET 6+ 的 MemoryCache.GetOrCreateAsync 内部已用 ConcurrentDictionary + 懒初始化锁机制,能确保同一 key 的 factory 只执行一次,其余并发请求自动等待并复用结果。
关键点:
GetOrCreateAsync 的 factory 返回 
Task,必须是异步加载逻辑(如调用数据库或 HTTP API),不能塞同步阻塞操作lock 或 SemaphoreSlim,这会抵消框架内置的协调能力var value = await _cache.GetOrCreateAsync("user:123", async entry =>
{
entry.SlidingExpiration = TimeSpan.FromMinutes(10);
return await _userService.GetUserByIdAsync(123); // 真实异步 IO
});
Refresh 而非 Set
如果业务要求“后台更新数据后立刻刷新缓存”,直接 Set 会覆盖正在被 GetOrCreateAsync 执行中的 factory,导致脏数据或异常。正确做法是调用 Refresh —— 它不改变值,只重置过期计时器,并标记该 entry 为“已刷新”,避免其他线程误判为过期而重复加载。
典型场景:用户资料修改成功后同步刷新缓存
Refresh("user:123") 安全,不会中断正在进行的 GetOrCreateAsync
Remove("user:123") 后再 Set 是危险的,可能引发瞬间大量并发回源GetOrCreateAsync 的 entry.SetOptions 重新设置过期策略缓存 key 是字符串,但业务中常拼接参数生成,比如 "order:" + orderId + ":summary"。高并发下若 key 生成逻辑含非线程安全状态(如静态 StringBuilder、共享变量),会导致 key 错乱,进而缓存污染或击穿。
$"order:{orderId}:summary",别用 string.Format 配共享格式器DateTime.Now.ToString("HHmm")),这会让缓存失效加速且无法共享HashCode.Combine(a, b, c) 生成 int 再转字符串,比 JsonSerializer.Serialize(obj) 更轻量且确定性更强PostEvictionCallbacks 中的并发副作用注册缓存淘汰回调(RegisterPostEvictionCallback)常用于清理关联资源,但回调执行时机不确定,且可能被多个线程并发触发(尤其当缓存批量清除时)。
ConcurrentDictionary 记录是否已处理过某 key 的淘汰Set 同一个 key——此时缓存已空,又没走 GetOrCreateAsync 的协调流程,极易引发竞态Refresh,95% 的高并发缓存问题就消失了。剩下那些,往往出在业务逻辑把缓存当数据库用了。