56

我试图了解等待异步在 C# 中的工作方式,而一件事让我很困惑。我知道任何使用 await 关键字的方法都必须用 async 标记。我的理解是,当点击带有 await 关键字的行时,该行下面的代码不会被执行。启动异步操作以执行 await 行中的语句,并将控制权返回给可以继续执行的调用方法。

问题#1:这个假设是正确的还是等待关键字下面的代码仍然被执行?

其次假设我调用了一个服务方法 async 并且需要返回它的结果。return 语句位于 await 关键字下方。

问题 #2:return 语句何时命中,在异步调用完成之后还是之前?

问题#3:我想使用该服务调用的结果,异步操作无济于事,因为我希望在返回结果时调用调用方法。我知道这可以使用使调用同步的 Result 属性来完成。但是,在数据库操作中使用异步是什么,因为它们实际上在大多数应用程序中占用了 80% 的时间。

问题 # 4:如何将异步与数据库操作一起使用?有可能并推荐吗?

问题#5:异步操作在哪种情况下有用,似乎每个api现在都在无缘无故地进行异步操作?还是我错过了使用异步操作的重点?

我的意思是说api无缘无故地制作异步方法是因为方法必须返回一些东西,直到计算出来它们如何返回,所以从本质上讲,调用不会在某种意义上仍然阻塞,直到它是无用的结果返回?

4

2 回答 2

59

MSDN解释了一切

我知道有时香草文档(特别是来自 MSDN)可能难以适用于您的特定情况,所以让我们回顾一下您的观点。

问题#1:这个假设是正确的还是等待关键字下面的代码仍然被执行?

“await”关键字下面的代码只会在异步调用完成时执行。同时,由于您的方法被标记为“异步”,因此控制权将返回给您的方法的调用者,直到您的方法完成。从上面的 MSDN 链接:

Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();

// The await operator suspends AccessTheWebAsync. 
//  - AccessTheWebAsync can't continue until getStringTask is complete. 
//  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
//  - Control resumes here when getStringTask is complete.  
//  - The await operator then retrieves the string result from getStringTask. 
string urlContents = await getStringTask;

我认为评论非常具有解释性。

其次假设我调用了一个服务方法 async 并且需要返回它的结果。return 语句位于 await 关键字下方。

问题 #2:return 语句何时命中,在异步调用完成之后还是之前?

后。

问题#3:我想使用该服务调用的结果,异步操作无济于事,因为我希望在返回结果时调用调用方法。我知道这可以使用使调用同步的 Result 属性来完成。但是,在数据库操作中使用异步是什么,因为它们实际上在大多数应用程序中占用了 80% 的时间。

假设您需要进行三个不相关的数据库查询来完成您的服务,然后根据结果进行计算,然后完成。如果您按顺序执行此操作,则必须等到每个操作完成。如果您使用异步调用,则 C# 将并行运行三个查询,您的服务可能会更快完成。

此外,返回 Task 的操作可以用作 Futures。请参阅有关 Futures 的 MSDN,其中讨论了有关如何基于 futures 并行化工作并合并结果的几种模式。

如果您的服务只需要一个数据库调用,那么将其称为异步肯定会更糟。

问题 # 4:如何将异步与数据库操作一起使用?有可能并推荐吗?

ADO.NET 现在包括异步方法ReadAsync 和 NextResultAsync

这绝对是可能的,因为推荐这个讨论比我在这里写的要完整得多。

问题#5:异步操作在哪种情况下有用,似乎每个api现在都在无缘无故地进行异步操作?还是我错过了使用异步操作的重点?

异步操作对于轻松并行化任何长时间运行的操作而不会遇到线程问题非常有用。如果您的方法只做一件事,或者一系列简单(快速)的事情,那么是的,异步是没有用的。但是,如果您有多个长时间运行的操作,则通过异步将它们并行化比管理线程要容易得多且不易出错。

于 2013-07-05T13:03:21.613 回答
15

您的大部分问题都在官方 文档和我写的介绍帖子中得到了解答。

问题 # 4:如何将异步与数据库操作一起使用?可能吗

Entity Framework 6(目前处于 Beta 版)支持async. 较低级别的数据库 API 以一种或另一种方式支持异步操作。其中一些(例如,SQLite)async直接支持;其他人需要您编写简单的async兼容包装器。

...并推荐?

是的,除非您正在编写一个前端服务器(例如,ASP.NET),它与后端的不可扩展的单一数据库机器通信。在那种特定情况下,使您的前端缩放没有意义,因为您的后端无论如何都无法缩放以匹配它。

问题#5:异步操作在哪种情况下有用,似乎每个api现在都在无缘无故地进行异步操作?还是我错过了使用异步操作的重点?

异步操作的好处是:

  1. 在客户端 (UI) 端,您的应用程序保持响应。
  2. 在服务器端,您的应用程序可以更好地扩展。
于 2013-07-05T13:48:44.357 回答