如何在C#中等待异步工作

时间:2013-07-05 12:14:23

标签: asynchronous async-await c#-5.0

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

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

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

问题2:在异步调用完成之后或之前,返回语句是什么时候命中的?

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

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

问题5:在哪个场景中,异步操作会有用,似乎每个api现在只是在没有理由的情况下进行异步操作?还是我错过了使用异步操作的意义?

我的意思是说api正在制作asyn方法而没有理由是因为方法必须返回一些东西并且直到计算得出它们如何返回所以在essense中这样的调用不会因为它将会阻塞在结果返回之前没用?

2 个答案:

答案 0 :(得分:56)

MSDN explains everything

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

  

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

“await”关键字下面的代码只会在异步调用完成时执行。同时,由于您的方法被标记为“async”,因此控制将返回给您的方法的调用者,直到您的方法完成。 从上面的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:在异步调用完成之后或之前,返回语句是什么时候命中的?

  

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

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

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

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

  

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

ADO.NET现在包含异步方法ReadAsync and NextResultAsync

这绝对是可能的,至于推荐,这个讨论比我写here要完整得多。

  

问题5:在哪个场景中,异步操作会有用,似乎每个api现在只是在没有理由的情况下进行异步操作?还是我错过了使用异步操作的意义?

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

答案 1 :(得分:14)

我的大多数问题都在official documentation以及我写的an intro post中得到了解答。

  

问题#4:如何在数据库操作中使用异步?是否可能

实体框架6(目前处于测试阶段)支持async。较低级别的数据库API以这种或那种方式支持异步操作。其中一些(例如,SQLite)直接支持async;其他人需要你编写简单的async - 兼容的包装器。

  

...并推荐?

是的,除非您正在编写与后端的不可扩展的单个数据库计算机对话的前端服务器(例如,ASP.NET)。在这种特定情况下,制作前端比例毫无意义,因为无论如何你的后端都无法进行缩放以匹配它。

  

问题5:在哪个场景中,异步操作会有用,似乎每个api现在只是在没有理由的情况下进行异步操作?还是我错过了使用异步操作的意义?

异步操作的好处是:

  1. 在客户端(UI)方面,您的应用程序仍然具有响应能力。
  2. 在服务器端,您的应用程序可以更好地扩展。