异步+等待==同步?


24

偶然发现了有关发出异步Web请求的帖子

除了简单性之外,如果在现实世界中,您所要做的就是发出一个异步请求并在下一行等待它,这与首先发出一个同步调用不是一样吗?


5
不完全是。从某种意义上讲,您的代码是同步的,直到获得结果,什么都不会发生。但是在下面,您可能会放弃正在运行的线程,直到返回异步方法,然后分配了另一个线程以继续执行。
R0MANARMY

2
是,但是有了异步,您可以同时执行另一个异步,然后等待2,异步就不可能了
棘手怪胎

这是一篇文章(tomasp.net/blog/async-compilation-internals.aspx),讨论了C#中异步的一些内幕 -这是涵盖C#和F#异步编程的系列文章的一部分。
paul 2013年

@ratchetfreak:是的,不用说您是否正在打多个电话。
Mrchief 2013年

@ R0MANARMY:如果您的应用程序正在执行其他操作,则可以,并通过async + await启用它。阿基姆说得最好!但是,请想象该代码不在button_click处理程序或任何此类事件处理程序中。如果有人盲目地将代码(异步+等待行)复制到任何方法,则可能导致假象,即您的代码是异步的,但实际上可能不是。
Mrchief 2013年

Answers:


32

不,async + await != sync是因为继续

来自MSDN,“使用Async和Await进行异步编程(C#和Visual Basic)”

异步方法旨在作为非阻塞操作。当等待的任务运行时,异步方法中的等待表达式不会阻塞当前线程。取而代之的是,表达式将方法的其余部分作为继续进行签名,并将控制权返回给async方法的调用者

例如,异步执行将不会阻止UI线程,并且Some TextBox.Text将在下载完成后进行更新

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}

说得很好!
Mrchief

您能详细解释一下吗?您是在说...如果没有这个...您将无法与UI交互...因为它将在主线程上。因此,这是否意味着它仅适用于与Web交互独立于Web服务器线程的Web应用程序。因此,仅在主线程为运行线程时,这才变得很重要,即不同步*。这是否会产生意外的行为,即在App(1主线程)中单击了两个按钮..但是您应该能够在没有第一个完成的情况下单击1?
Seabizkit '16

Console.WriteLine(await GetStringOverNetwork());呢 如果您需要异步调用的输出怎么办?即使线程可能继续执行,程序在第一次访问时也会阻塞吗?
安德鲁

6

不,不一样。

您的async代码块正在等待await调用返回继续,但是您的应用程序的其余部分没有等待,并且仍然可以像往常一样继续。

相反,同步调用将使您的整个应用程序或线程等待,直到代码执行完毕才能继续执行其他任何操作。


同步呼叫无法实现为async + await吗?
棘轮怪胎

@ratchetfreak我认为设置await / async会有一些开销,所以我认为您不希望使用它编写整个应用程序。我仅将其用于执行可能长时间运行的代码块,因此它不会锁定我的应用程序。:)
Rachel

5

请允许我澄清有关异步/等待的事情。

遇到等待状态时,基础状态机允许立即返回控制。然后,当等待的呼叫完成时,基础状态机允许在等待的呼叫之后的那一行恢复执行。

因此,异步块不会被阻塞,也不会等待已完成的调用。遇到await命令时,将立即返回控制。

底层状态机是使用async / await背后的“魔术”的一部分,它不会被废弃或遗漏。


2

我偶然想到了同样的问题,但在阅读了回答后,这个问题似乎依然存在,并被“引擎盖下的魔术”所迷惑。

通过上述异步编程

  • async关键字把一个方法为异步方法,它允许你使用await关键词在它的身上。
  • await应用关键词时,它暂停调用方法和产量控制返回给调用者直到等待任务完成。
  • await只能在方法内部使用async

遇到的上下文是否await被阻止?

  • 是的。从本质上讲,这是在执行上下文中维护已知状态的本地同步屏障。除非其他上下文(如果有)未加入。

应用程序的其余部分是否在处阻塞await

  • 这取决于您的应用程序的编写方式。如果是await在相同上下文中按顺序启动的一系列相关ed任务(请参阅:试图了解一些异步/等待行为

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    这样,每个对象await都会阻止下一个对象的生成。

    另一方面,并​​行启动的相同从属任务将并行执行,并且上下文只会在响应时阻塞。await

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    通常,await产生执行到外部上下文,从该外部上下文调用当前上下文。但是,如果外部上下文本身正在等待当前电流,则就像await在同一上下文中的s一样。

因此,为了获得async好处,需要将应用程序设计为运行多个并行上下文(UI,数据客户端等),然后await在一个上下文中产生对其他上下文的执行,因此整个应用程序不会在单个对象上阻塞await

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.