是异步还是等待基于GUI的异步编程?

dia*_*ler 35 .net c# async-await

我一直在阅读C#中的新操作符asyncawait操作符,并试图找出它们可能对我有用的环境.我研究了几篇MSDN文章,这里是我在线之间阅读的内容:

您可以使用asyncWindows窗体和WPF事件处理程序,因此在执行大量操作时,它们可以执行冗长的任务而不会阻止UI线程.

async void button1_Click(object sender, EventArgs e)
{
    // even though this call takes a while, the UI thread will not block
    // while it is executing, therefore allowing further event handlers to
    // be invoked.
    await SomeLengthyOperationAsync();
}
Run Code Online (Sandbox Code Playgroud)

使用await必须的方法async,这意味着async在代码中某处使用任何函数最终会强制调用序列中的所有方法从UI事件处理程序到最低级别的async方法async.

换句话说,如果您创建一个带有普通旧旧ThreadStart入口点的线程(或者具有良好旧版本的Console应用程序static int Main(string[] args)),那么您将无法使用async,await因为您必须await使用它async,并使用它的方法,并且因此在调用方法中你还必须使用await并制作那个async,依此类推.但是一旦你到达线程入口点(或Main()),就没有await可以控制的调用者.

所以基本上你不能使用asyncawait没有使用标准WinForms和WPF消息循环的GUI.我猜这一切确实有意义,因为MSDN声明async编程并不意味着多线程,而是使用UI线程的空闲时间; 当使用控制台应用程序或具有用户定义入口点的线程时,需要多线程来执行异步操作(如果不使用兼容的消息循环).

我的问题是,这些假设是否准确?

Jon*_*eet 28

所以基本上你不能使用async和await而没有使用标准WinForms和WPF消息循环的GUI.

绝对不是这样的.

在Windows窗体和WPF中,async/ await具有在您等待的异步操作完成时返回UI线程的便利属性,但这并不意味着它是唯一的目的.

如果异步方法在线程池线程上执行 - 例如在Web服务中 - 则继续(异步方法的其余部分)将在任何线程池线程中执行,并且适当地保留上下文(安全性等).这对于保持线程数量下降仍然非常有用.

例如,假设您拥有高流量Web服务,该服务主要代理对其他Web服务的请求.它花费大部分时间等待其他事情,无论是由于网络流量还是在其他服务(例如数据库)的真实时间.你不应该需要很多线程 - 但是通过阻塞调用,你自然会得到每个请求的一个线程.使用async/await,你最终会得到很少的线程,因为很少有请求实际上需要在任何一个时间点为它们执行任何工作,即使有很多请求"在飞行中".

问题是async/await最容易用UI代码演示,因为每个人都知道正确使用后台线程或在UI线程中做太多工作的痛苦.这并不意味着它是该功能唯一有用的地方 - 远非如此.

各种服务器端技术(例如MVC和WCF)已经支持异步方法,我希望其他人也能效仿.

  • 现在我已经阅读了所有答案,我想我知道哪里出错了.我得到的是它基本上是基于回调的常规编程,但代码更好.我假设`await` magic使用严格的GUI相关的东西来知道调用回调的位置(即`await`之后的方法的其余部分),而是使用`SynchronizationContext.Current`,`TaskScheduler.Current`,和"操作系统认为合适的任何东西",例如ThreadPool,按此顺序排列优先顺序.不幸的是,我是那种不习惯使用我自己无法编程的人的人. (2认同)

Jam*_*ing 8

使用await的方法必须是异步的,这意味着在代码中某处使用任何异步函数最终会强制调用序列中的所有方法从UI事件处理程序开始,直到最低级异步方法为异步.

不正确 - 标记为异步的方法只是意味着它们可以使用等待,但这些方法的调用者没有限制.如果方法返回,Task或者Task<T>他们可以使用ContinueWith或其他任何你可以用4.0中的任务

一个很好的非UI示例是MVC4 AsyncController.

最终,async/await主要是关于编译器的重写,因此您可以编写看似同步代码的内容,并避免在添加async/await之前必须执行的所有回调.它还有助于SynchronizationContext处理,对于具有线程关联性的场景(UI框架,ASP.NET)很有用,但即使没有这些,它仍然有用.例如,主要可以做DoStuffAsync().Wait();.:)


Ste*_*ary 6

我的问题是,这些假设是否准确?

没有.

您可以对Windows窗体和WPF事件处理程序使用async,这样它们可以执行冗长的任务,而不会在执行大量操作时阻止UI线程.

真正.其他UI应用程序也是如此,包括Silverlight和Windows Store.

而且确实为ASP.NET.在这种情况下,它是未被阻止的HTTP请求线程.

使用await的方法必须是异步的,这意味着在代码中某处使用任何异步函数最终会强制调用序列中的所有方法从UI事件处理程序开始,直到最低级异步方法为异步.

这是一种最佳实践(" async一直向下"),但并不是严格要求的.您可以阻止异步操作的结果; 许多人选择在控制台应用程序中执行此操作.

一个普通的好老ThreadStart入口点

嗯......我不得不接受"普通好老"的问题.正如我在博客上解释的那样,Thread几乎是你做背景操作的最糟糕的选择.

我建议您查看我的介绍asyncawait,并跟进async/ awaitFAQ.