ChatGPT解决这个技术问题 Extra ChatGPT

什么时候应该在 ASP.NET MVC 中使用异步控制器?

我对在 ASP.NET MVC 中使用异步操作有些担心。它何时会提高我的应用程序的性能,何时不会?

在 ASP.NET MVC 中随处使用异步操作是否很好?关于可等待的方法:当我想查询数据库(通过 EF/NHibernate/其他 ORM)时,我应该使用 async/await 关键字吗?我可以在一个操作方法中使用 await 关键字异步查询数据库多少次?


P
Peter Ritchie

您可能会找到我的MSDN article on the subject helpful;我在那篇文章中花了很多篇幅描述何时应该在 ASP.NET 上使用 async,而不仅仅是如何在 ASP.NET 上使用 async

我对在 ASP.NET MVC 中使用异步操作有些担心。什么时候可以提高我的应用程序的性能,什么时候不可以。

首先,了解 async/await 的全部意义在于释放线程。在 GUI 应用程序上,主要是关于释放 GUI 线程,以便用户体验更好。在服务器应用程序(包括 ASP.NET MVC)上,主要是关于释放请求线程,以便服务器可以扩展。

特别是,它不会:

让您的个人请求更快地完成。事实上,他们会完成(只是一点点)更慢。

当您点击等待时返回调用者/浏览器。 await 只向 ASP.NET 线程池“屈服”,而不向浏览器“屈服”。

第一个问题是 - 在 ASP.NET MVC 中随处使用异步操作是否很好?

我会说在你进行 I/O 的任何地方都可以使用它。不过,它可能不一定是有益的(见下文)。

但是,将它用于受 CPU 限制的方法是不好的。有时开发人员认为他们可以通过在控制器中调用 Task.Run 来获得 async 的好处,这是一个可怕的想法。因为该代码最终通过占用另一个线程来释放请求线程,所以根本没有任何好处(事实上,他们正在承担额外线程切换的惩罚)!

当我想查询数据库(通过 EF/NHibernate/其他 ORM)时,我应该使用 async/await 关键字吗?

您可以使用任何可用的等待方法。目前大多数主要参与者都支持 async,但也有一些不支持。如果您的 ORM 不支持 async,则不要尝试将其包装在 Task.Run 或类似的东西中(见上文)。

请注意,我说“你可以使用”。如果您谈论的是具有单个数据库后端的 ASP.NET MVC,那么您(几乎可以肯定)不会从 async 中获得任何可伸缩性优势。这是因为 IIS 可以处理比单个 SQL 服务器(或其他经典 RDBMS)实例多得多的并发请求。但是,如果您的后端更现代 - SQL 服务器集群、Azure SQL、NoSQL 等 - 并且您的后端可以扩展,并且您的可扩展性瓶颈是 IIS,那么您可以从 { 1}。

第三个问题 - 我可以在一个单一的操作方法中使用 await 关键字异步查询数据库多少次?

你喜欢多少就多少。但是,请注意,许多 ORM 具有每个连接一个操作的规则。特别是,EF 只允许每个 DbContext 进行单个操作;无论操作是同步的还是异步的,都是如此。

另外,请再次记住后端的可扩展性。如果您正在访问 SQL Server 的单个实例,并且您的 IIS 已经能够使 SQLServer 保持满负荷运行,那么对 SQLServer 施加双倍或三倍的压力根本不会对您有所帮助。


@seebiscuit:在进行(适当的异步)I/O 时,不使用线程。我有一个更详细的 blog post
IIS 和单个 SQL Server 实例可以处理多少个请求?我怎样才能找到这些数字?
@MOD:这取决于配置和硬件。找到这些数字的唯一方法是在您自己的服务器上进行负载测试。
@Flezcano:完全在 CPU 上执行的方法。即,它们不进行 I/O 或阻塞。
对不起,先生,但我不会接受我试图理解的这 2 个线性问题。当我研究这个问题时,比如我有 1 个 Web api 端点同时被 1000 个用户调用,那么这个端点将能够为这千个请求中的每一个提供服务器,或者我应该使其异步处理 1000 个请求?
T
Tharif

当一个动作必须执行几个独立的长时间运行的操作时,异步动作方法很有用。

AsyncController 类的典型用途是长时间运行的 Web 服务调用。

我的数据库调用应该是异步的吗?

IIS 线程池通常可以处理比数据库服务器更多的并发阻塞请求。如果数据库是瓶颈,异步调用不会加快数据库响应。如果没有节流机制,通过使用异步调用有效地将更多工作分派给不堪重负的数据库服务器只会将更多的负担转移到数据库上。如果您的数据库是瓶颈,那么异步调用将不是灵丹妙药。

应该查看 12 参考文献

源自@PanagiotisKanavos 评论:

此外,异步并不意味着并行。异步执行使有价值的线程池线程免于对外部资源的阻塞,而没有复杂性或性能成本。这意味着同一台 IIS 机器可以处理更多并发请求,而不是它会运行得更快。您还应该考虑阻塞调用以 CPU 密集型自旋等待开始。在压力时期,阻塞呼叫将导致不断升级的延迟和应用程序池回收。异步调用只是避免了这种情况


关于 async、IIS 和数据库,博文太老了,这里得出的结论是错误的。 IIS 必须处理比数据库更大的负载,线程池线程受到限制,长请求队列可能导致 500 个。在等待 IO 时释放线程的任何事情都是有益的。甚至链接也不是关于OP所要求的。事实上,同样的作者已经写道,你应该尽可能地使用异步 DB 方法
此外,异步并不意味着并行。异步执行使有价值的线程池线程免于对外部资源的阻塞,而没有复杂性或性能成本。这意味着同一台 IIS 机器可以处理更多并发请求,而不是它会运行得更快。
您还应该考虑阻塞调用以 CPU 密集型自旋等待开始。在压力时期,阻塞呼叫将导致不断升级的延迟和应用程序池回收。异步调用只是避免了这种情况
由于这是公认的答案,因此对于大多数人来说都是最重要的,因此删除关于执行时间和并行运行的第二段可能是明智的,这与异步无关。我意识到最后有一个注释,但这很容易引起误解。
异步执行仅在线程真正异步到实现的最底层时才释放线程,并使用一些回调机制来表示准备就绪并启动一个新线程来切换上下文并处理结果。所以,我不确定在哪种情况下这种上下文切换/新线程创建比仅在单个线程中等待结果更有效?无论如何,长时间运行的 Web 服务调用是一个坏主意,我更喜欢将其卸载到可靠的后台服务并让客户端检查结果,这可能会在几分钟、几小时或几天内出现。
Y
Yuval Itzchakov

在 ASP.NET MVC 中随处使用异步操作是否很好?

像往常一样编程,这取决于。沿着某条路走下去,总会有一个权衡。

async-await 在您知道自己会收到对服务的并发请求并且希望能够横向扩展的地方大放异彩。 async-await 如何帮助横向扩展?事实上,当您同步地调用异步 IO 调用时,例如网络调用或访问您的数据库,负责执行的当前线程被阻塞,等待请求完成。当您使用 async-await 时,您可以让框架为您创建一个状态机,以确保在 IO 调用完成后,您的方法会从中断处继续执行。

需要注意的是,这个状态机有一个微妙的开销。使方法异步并不能使其执行得更快,这是一个需要理解的重要因素,也是许多人的误解。

使用 async-await 时要考虑的另一件事是它一直是异步的,这意味着您将看到异步渗透到整个调用堆栈,从上到下。这意味着如果您想公开同步 API,您经常会发现自己复制了一定数量的代码,因为 asyncsync 不能很好地混合。

当我想查询数据库(通过 EF/NHibernate/其他 ORM)时,我应该使用 async/await 关键字吗?

如果您选择使用异步 IO 调用,那么是的,async-await 将是一个不错的选择,因为越来越多的现代数据库提供程序公开了实现 TAP(任务异步模式)的异步方法。

ONE single action 方法中,我可以使用 await 关键字异步查询数据库多少次?

只要您遵循数据库提供商规定的规则,您想要多少就多少。您可以进行的异步调用数量没有限制。如果您有相互独立且可以同时进行的查询,您可以为每个查询旋转一个新任务并使用 await Task.WhenAll 等待两者完成。


异步数据库调用不会执行得更快,但允许同一台 IIS 机器处理更多请求,因为不会浪费线程池线程。它还降低了 CPU 成本,因为阻塞调用实际上是在实际阻塞之前以 CPU 密集型 spinwait 开始的。在高负载情况下,这可能是机器挣扎或故障与回收之间的区别
@PanagiotisKanavos 我知道,我说的不清楚吗?
您的回答没有提到 IIS 细节 - 崩溃/回收场景是始终使用异步的主要原因。没有经历过的人可能不会理解scale out well可能意味着your server won't die under load。或者可能是 once burned ...
C
Community

async 当操作对 DB 或某些网络绑定调用执行某些 I\O 操作时,其中处理请求的线程将在从您刚刚调用的数据库或网络绑定调用获得响应之前停止,这些操作最有帮助。最好将 await 与它们一起使用,它会真正提高应用程序的响应能力(因为在等待 DB 或任何其他类似操作时会停止更少的 ASP 输入\输出线程)。在我的所有应用程序中,每当非常需要对 DB 进行多次调用时,我总是将它们包装在可等待的方法中,并使用 await 关键字调用它。


b
bohdan_trotsenko

我的 5 美分:

当且仅当您执行 IO 操作时使用 async/await,例如 DB 或外部服务 web 服务。总是更喜欢对 DB 进行异步调用。每次查询数据库时。

PS 第 1 点有例外情况,但您需要对此有一个很好的异步内部理解。

作为一个额外的优势,如果需要,您可以并行执行少量 IO 调用:

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result

j
jpaugh

如您所知,MVC 支持异步控制器,您应该利用它。如果您的控制器执行了一个冗长的操作(可能是基于磁盘的 I/O 或对另一个远程服务的网络调用),如果请求以同步方式处理,则 IIS 线程一直都很忙。结果,线程只是在等待冗长的操作完成。在第一个请求的操作正在进行时,通过服务其他请求可以更好地利用它。这将有助于服务更多并发请求。您的网络服务将具有高度可扩展性,并且不会轻易遇到 C10k problem。对数据库查询使用 async/await 是个好主意。是的,您可以根据需要多次使用它们。

查看 here 以获得出色的建议。


g
gajama

我的经验是,今天很多开发人员使用 async/await 作为控制器的默认设置。

我的建议是,只有当你知道它会对你有帮助时才使用它。

原因是,正如 Stephen Cleary 和其他人已经提到的那样,它可能会引入性能问题,而不是解决它们,并且它只会在特定情况下为您提供帮助:

高流量控制器

可扩展的后端


S
Shadi Alnamrouti

在 ASP.NET MVC 中随处使用异步操作是否很好?

在可以使用异步方法的任何地方都这样做是很好的,尤其是当您在工作进程级别遇到大量数据和计算操作的性能问题时。否则,不需要,因为单元测试需要强制转换。

关于可等待的方法:当我想查询数据库(通过 EF/NHibernate/其他 ORM)时,我应该使用 async/await 关键字吗?

是的,最好尽可能将异步用于任何数据库操作,以避免工作进程级别的性能问题。请注意,EF 为大多数操作创建了许多异步替代方案,例如:

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

我可以在一个操作方法中使用 await 关键字异步查询数据库多少次?

天空才是极限


大多数 Web 应用程序的业务逻辑通常需要高度顺序的操作,因此在大多数情况下,并行进程之间的跳转仅在 Web 请求/工作进程管理的最顶层是可行的,它无论如何都不会直接处理数据库请求。我真的很想看到一些典型 Web 应用程序的真实示例,在这些示例中,以异步方式处理 DB 查询实际上是一个好主意。