【问题标题】:Is async and await exclusively for GUI-based asynchronous programming?async 和 await 是否专门用于基于 GUI 的异步编程?
【发布时间】:2016-05-09 14:50:35
【问题描述】:

我一直在阅读 C# 中新的 asyncawait 运算符,并试图弄清楚它们在哪些情况下可能对我有用。我研究了几篇 MSDN 文章,以下是我在字里行间读到的内容:

您可以将async 用于 Windows 窗体和 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();
}

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

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

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

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

【问题讨论】:

  • +1 提出了一个好问题,即使它完全误解了文档:)
  • 查看一些非 GUI 示例 here

标签: c# .net async-await


【解决方案1】:

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

绝对不是

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

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

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

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

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

【讨论】:

  • 现在我已经阅读了所有答案,我想我知道我哪里出错了。我做对的是它基本上是常规的基于回调的编程,但代码更好。我假设 await 魔术使用与 GUI 严格相关的东西来知道在哪里调用回调(即在 await 之后的方法的其余部分),而它使用 SynchronizationContext.CurrentTaskScheduler.Current 和“任何东西操作系统认为合适”例如ThreadPool,按该顺序排列优先级。不幸的是,我是那种不习惯使用我自己无法编程的东西的人。
  • @dialer:想要窥探魔法背后的一切并没有错。您可能会喜欢我的 Eduasync 博客系列:msmvps.com/blogs/jon_skeet/archive/tags/Eduasync/default.aspx
  • 更新了 Eduasync 系列开始的链接(其他链接对我不起作用):blogs.msmvps.com/jonskeet/2011/05/08/…
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

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

    没有。

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

    没错。其他 UI 应用程序(包括 Silverlight 和 Windows 应用商店)也是如此。

    并且适用于 ASP.NET。在这种情况下,是 HTTP 请求 线程没有被阻塞。

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

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

    一个普通的好旧 ThreadStart 入口点

    嗯...我确实不得不对“普通的好老人”提出异议。正如我在博客中解释的那样,Thread is pretty much the worst option you have for doing background operations

    我建议您查看我的introduction to async and await,并跟进async / await FAQ

    【讨论】:

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

      【讨论】:

        猜你喜欢
        • 2020-07-26
        • 1970-01-01
        • 2013-04-11
        • 2019-05-10
        • 1970-01-01
        • 2016-12-04
        • 2020-11-19
        • 2015-12-19
        • 1970-01-01
        相关资源
        最近更新 更多