【问题标题】:ASP.NET Core MemoryCache GetOrCreateAsync overhead of async and awaitASP.NET Core MemoryCache GetOrCreateAsync 的 async 和 await 开销
【发布时间】:2025-12-13 17:55:02
【问题描述】:

先说一点上下文:

目前,我们使用的是 ASP.NET Core MemoryCache MemoryCache Doc

IMemoryCache 接口上有一个名为GetOrCreateAsync(...) 的方法,我可以在其中传入工厂函数Func<ICacheEntry, Task<TItem>> factory

由于这是一个异步方法签名,我必须一直实现async await(有时是大约 8 个方法的调用堆栈),即使缓存命中本身是同步的。在我的场景中,每个请求我访问了大约 200-2500 次缓存。有些条目我必须每 60 分钟刷新一次,有些则每天都要刷新。

现在的问题:

我目前的理解是,.NET Core 必须为每个调用创建一个状态机,即使我只是以同步方式访问缓存,因为它的方法签名。你们当中有人知道这有多大的开销吗?创建一个带有一点阻塞的同步工厂(它是一个 Web-API 调用)以便我可以使用GetOrCreate(...) 是否更有意义?或者也许你们中的一些人有完全不同的想法。

希望你能明白我的痛点。

【问题讨论】:

  • ericlippert.com/2012/12/17/performance-rant(比较GetOrCreateAsyncGetOrCreate
  • "....NET Core 必须创建状态机..."。不,.NET Core 与 async 和 await 完全无关。执行此操作的是 c# 编译器,而不是运行时
  • async await performance?的可能重复
  • @VSDekar 您完成研究并查看有关某个主题的现有资源并尝试自己解决您的问题之后,您应该提出有关 SO 的问题。
  • @Servy 相信我,我已经做了很多研究。对于使用了 100 次的非常具体的产品,我试图尽可能准确地表达我的问题。如果我可以用一个问题为自己节省几个小时来实现类似的事情,那么我认为值得一试。我只想问是否有人已经对他们自己的解决方案中的MemoryCache有所了解。

标签: c# asynchronous asp.net-core async-await


【解决方案1】:

你在这里有很多困惑。首先也是最重要的,委托不是异步委托,而是任务返回委托。通常将两者混为一谈,因为您通常只从异步操作返回任务,但您不必这样做。为了满足委托,您只需使用Task.FromResult(foo),其中foo 是您最终返回的任何内容。重要的是,该返回可以同步满足,因此,如果底层进程是同步的,那么从这里开始就完全不需要涉及 async/await。

其次,await 默认会创建一个SynchronizationContext。这在线程切换的情况下存在,因为任何线程本地的东西都需要移动到新线程以防止丢失引用。这涉及向堆中添加东西,是的,会降低性能。但是,如果您没有使用线程局部变量和/或不可能进行线程切换,则不需要这个。在这种情况下,您可以在异步方法上调用ConfigureAwait(false)。特别是 ASP.NET Core,根本不使用线程本地(通过依赖注入满足横切依赖)。因此,使用ConfigureAwait(false)始终安全的,您实际上应该将其添加到您执行的每个异步操作中。在这种特殊情况下,SynchronizationContext 毫无用处,因为您的操作是同步的,这意味着无论如何都不会发生线程切换。

【讨论】: