2016-06-17 40 views
1

据我所知,C#中的async/await功能将await调用之间的段拆分为在每个等待方法在单独返回后在调用线程上运行的回调方法工作者线程。调用线程在等待期间是“免费”的。回调必须通过某种事件循环在调用线程上安排。在控制台或网络应用程序中使用async/await

此事件循环仅存在于Windows窗体或WPF等GUI应用程序中。释放此循环可确保UI在长时间操作期间保持对其他用户交互的响应。

控制台应用程序和Web应用程序(ASP.NET)没有这种事件循环,所以此回调机制不起作用。但是再次,他们没有事件循环,因为他们不需要循环。没有用户随时试图与正在运行的程序进行交互,期待即时反馈。所以没有必要为此释放调用线程。操作使用多少个线程并不重要,它只在最后一位完成后才返回。

那么在控制台和网络应用程序中使用asyncawait还是一般的任何非交互式代码,比如Windows服务?与简单的同步调用相比,它有什么不同或更高效?

我正在设计一个由GUI和非交互式(服务和Web)程序使用的API,并且很难理解它在非GUI环境中的行为。

+3

如果您不想每个IO操作都使用一个线程,那么它仍然非常有用。正确完成后,通过执行异步操作,只需少量线程即可处理数百个并发IO操作。 – spender

回答

3

具有异步等待点的是,当您到达第一个异步点(即未完成任务的第一个await)时,调用线程为总是释放。

在UI应用程序中,您有一个SynchronizationContext,它在等待到UI线程后发布代码,因为与UI交互的代码必须由UI线程执行,否则您将得到一个异常。你可以通过使用ConfigureAwait(false)来控制它。

在控制台应用程序(和服务等)中没有这样的需要,因此代码在一些ThreadPool线程上运行。调用线程(这可能也是一个ThreadPool线程)被释放,并且能够在同时进行其他类型的工作,而不是同步阻塞。所以异步等待提高了可伸缩性,因为它可以使用相同数量的线程进行更多的工作。

+0

为了提高可伸缩性,异步仅用于I/O绑定的工作,而不是CPU绑定的工作,对吗?因为一个或另一个线程是否完成这项工作并不重要。只有当一个线程被阻塞或释放并且在I/O操作完成时重新激活时才是重要的。所以这意味着,我只需要在I/O工作中使用异步API,而不需要长时间计算。 – ygoe

0

异步/等待无关与多线程,引用MSDN

异步和等待关键字不会导致被 创建额外的线程。异步方法不需要多线程,因为异步方法不会在其自己的线程上运行。

Async/await允许您针对长时间运行操作(可能是CPU工作或I/O工作)构造代码。所以这适用于任何类型的程序(GUI,Web服务,控制台等)

1

i3arnon's answer是(像往常一样)优秀。

那么控制台和网络应用程序或任何类型的非交互式代码(如Windows服务)中的异步和等待有什么用处?

异步客户端的主要好处是响应能力;服务器端异步的主要好处是可伸缩性。

与简单同步调用相比,它有什么不同或更高效?

客户端响应能力和服务器端可伸缩性是通过相同的机制实现的:释放调用线程。因此,异步就是使用更少的线程。在服务器端,使用较少的线程可以让您的应用程序最大限度地利用现有的线程池。

据我所知,C#中的异步/等待功能将await调用之间的段分割为在每个等待方法在单独的工作线程上返回后在调用线程上运行的回调方法之间的段。

这就是我回答的原因。我不能让这一个去。每次在此理解中提到“线程”时,都是错误的。这部分是正确的:await将“拆分”async方法分段。

1)回调方法不在调用线程上运行。相反,await将捕获“上下文”并恢复该上下文中的方法。在ASP.NET应用程序和控制台应用程序中,上下文并不意味着特定的线程。我解释了await如何在我的async intro blog post上详细记录上下文。

2)异步API通常不在工作线程上执行。异步的全部要点是释放线程,所以阻塞线程池线程是没有意义的。我在我的博客文章There Is No Thread上解释了异步I/O如何几乎没有线程。

相关问题