38

我一直在阅读 C# 中的 newasyncawait运算符,并试图弄清楚它们在哪些情况下可能对我有用。我研究了几篇 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();
}

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

换句话说,如果您创建一个具有普通 good oldThreadStart入口点的线程(或具有 good old 的控制台应用程序static int Main(string[] args)),那么您不能使用asyncandawait因为在某一时刻您必须使用await, 并制作使用它的方法async,并且因此,在调用方法中,您还必须使用await并制作该方法async,依此类推。但是,一旦您到达线程入口点(或Main()),就没有调用者await可以让其控制。

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

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

4

4 回答 4

29

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

绝对不是这样的。

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

如果异步方法在线程池线程上执行 - 例如在 Web 服务中 - 那么延续(异步方法的其余部分)将简单地在任何线程池线程中执行,并适当地保留上下文(安全等)。这对于减少线程数量仍然非常有用。

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

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

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

于 2012-09-29T17:47:51.673 回答
8

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

不正确 - 标记为 async 的方法只是意味着它们可以使用 await,但这些方法的调用者没有限制。如果方法返回Task,或者Task<T>他们可以使用ContinueWith或您可以在 4.0 中对任务执行的任何其他操作

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

归根结底,async/await 主要是为了让编译器重写,这样你就可以编写看起来像同步的代码,并避免像在添加 async/await 之前必须做的所有回调。它还有助于处理 SynchronizationContext,这对于具有线程关联(UI 框架、ASP.NET)的场景很有用,但即使没有这些,它仍然很有用。例如, Main 总是可以做DoStuffAsync().Wait();的。:)

于 2012-09-29T18:01:39.953 回答
6

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

不。

您可以将异步用于 Windows 窗体和 WPF 事件处理程序,因此它们可以执行冗长的任务,而不会在执行大部分操作时阻塞 UI 线程。

真的。对于包括 Silverlight 和 Windows 应用商店在内的其他 UI 应用程序也是如此。

对于 ASP.NET也是如此。在这种情况下,未阻塞的是HTTP 请求线程。

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

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

一个普通的好旧 ThreadStart 入口点

嗯...我确实不得不对“普通的好老人”提出异议。正如我在博客上解释的那样,Thread这几乎是您进行后台操作的最糟糕的选择。

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

于 2012-09-29T19:02:14.960 回答
0
  1. async-await 只是 Task 类操作的包装器,它是所谓的 Tasks Parallel Library - TPL 的一部分(在 async-await 自动代码生成技术之前发布。)
  2. 所以事实上你不能在 async - await 中使用对 UI 控件的任何引用。
  3. 通常,async-await 是任何 Web 和服务器关系、加载资源、sql 的强大工具。它适用于具有活动 UI 的智能等待数据。
  4. 典型的 TPL 应用:从简单的大循环到基于共享数据的复杂计算中的多阶段并行计算(ContinueWith 等)
于 2015-11-02T20:08:29.837 回答