使控制器方法异步会提高其性能吗?有什么好处?

Will making a controller method async improve its performance? What is the benefit?

免责声明:我已经仔细考虑过这个问题是否是基于意见的,因为我明白遵守网站规则的重要性。我的结论是它足够具体,可以在这里回答。如果我接受纠正,我深表歉意。

我选择在没有 asyncTask 的情况下编写我的控制器。我认为,由于两个原因,异步操作没有任何好处。

  1. 一次提供整个视图模型,在准备好呈现整个内容(即没有列表逐渐传输)之前,没有任何有意义的信息可以呈现。

  2. 服务中的操作需要进行一些繁重的数据处理,并且基于假设了解所有检索到的元素并在公开之前存储某些信息的逻辑(即没有SaveChangesAsync() 等是可能的,并且使用 AsNoTracking() 存在)。

描述视图模型的 class 大致如此。

public class TheViewModel
{
  public string Name { get; set; }
  public byte[] Pieces { get; set; }
  public Guid Id { get; set; }
  public Dictionary<int, Info> { get; set; }
}

public class Info
{
  public Guid Id { get; set; }
  public Guid ParentLeftId { get; set; }
  public Guid ParentRightId { get; set; }
  public Guid ParentRandId { get; set; }
  public int[] Data { get; set; }
  public List<DateTime> { get; set; }
}

我的一位同事对我的选择眨了眨眼睛,并争辩说:

一个。这不是推荐的方式, b.该操作将执行效率较低, C。这违反了最佳实践。

我们用谷歌搜索并阅读了很多博客。总体印象表明该论点是有效的。但是,我质疑它在我们案例中的相关性。 Prestanda 不是一个民主问题,不能以意见为基础。

当我试图查找实际参考资料(MSDN、SO 等)时,其中说明性能会受到多大影响,但我得到的很少。我也没有找到太多关于如何可靠地测试它的信息。

The whole view model is served at once and there's no meaningful information to present until the whole content is ready to be rendered

这实际上不是问题所在。

您可能在某处从数据库获取信息(您提到保存更改。)如果您异步与数据库交互(例如 ExecuteDataReaderAsync),则等待它意味着查询正在执行执行查询的线程可以做其他事情。当查询完成执行时,该线程(或另一个无关紧要的线程)将结束。

允许线程在查询时执行其他操作,而不是只等待,这样可以提高应用程序的性能。

这里是我认为混乱的来源:async/await 如何使您的控制器方法执行得更快? 没有。一点也不。事实上,让一个线程在像这样的任务之间切换可能会使它稍微慢一点。 (这通常是微不足道的,您不必担心。)

但总体而言,您的应用程序的性能可以更快,因为无论有多少线程可用 - 即使只有一个 - 它们有可能正在做某事而不是等待.

您正在做的个别事情(例如执行控制器方法)并没有更快,但是您让应用程序有机会利用它拥有的每个线程做更多事情。不管花费多长时间,它可能会更快开始,因为它不等待线程,这意味着它完成得更快,而不是更快。

即使您的应用程序一次接收到一个请求并仅使用一个线程处理它,下面是一个场景:如果您发出两个数据库或 API 请求,而这两个请求都不依赖于另一个的结果怎么办?如果您同步处理它们,您将等待一个完成,开始下一个,然后等待下一个完成。如果您异步处理它们,则启动一个,在等待期间可以启动下一个。两项单独的任务都不会发生得更快。不同之处在于第二个任务开始得更快 - 而与第一个任务无关,只能等待。

所以当我们谈论 "threads," 时,它并不是关于多线程的。这是关于如何使用每个单独的线程。

我会尝试用不同的方式解释这一点。

Async/await 通常有助于 IO 操作。这些包括(但不限于):访问文件、访问数据库、调用 Web 服务、使用网络套接字做一些事情,甚至访问一些特殊的硬件,如扫描仪。基本上,在某些时间点,您的代码需要 等待 某些外部操作的结果 - 文件读取操作、SQL 查询、HTTP 请求等等。

这就是 async/await 的帮助。没有它,您的线程会卡住等待结果,这通常会花费很长时间。但是有了它,您的线程就可以在等待时切换到做其他事情。因此,您的 CPU 可以更有效地使用。

注意 - 这不是多线程。没有 "actually does the work" 的附加线程。相反,在所有抽象层的深处,计算机正在等待一些硬件返回报告——硬盘驱动器、网络适配器,等等。 (好吧,是的,你 可以 也等待另一个线程完成它正在做的事情,但这是一种相当罕见的情况)

在您的方案中,使用 async/await 您可以使用单个线程处理两个传入的 REST 请求。你会从第一个开始,然后它会到达需要等待的地步(比如,因为它正在执行一个 SQL 查询),然后 ASP.NET 会切换到第二个一。然后,当第二个等待(或可能完成)时,ASP.NET 将检查 SQL 结果是否存在,并且它可以继续第一个。您的线程永远不会同时处理多个请求,但它会在它们之间来回切换——每当一个等待时,它就会继续另一个。从而提高效率。

请注意,如果您的请求在 CPU 上花费的时间比它们在等待某些外部 IO 上花费的时间更多,那么您从 async/await 中获得的收益会更小。如果您根本不执行 no IO(例如您的结果仅取决于请求内容),那么您确实不需要任何 async/await 因为没有什么可等待的。

即使您找到 async/await 的用途,它也不会帮助任何单个请求处理更快 - 它只会让您同时处理更多请求。