47

Stumbled upon this post that talks about making async web requests.

Now simplicity aside, if in real world, all you do is make an async request and wait for it in the very next line, isn't that the same as making a sync call in the first place?

Mrchief
  • 621
  • 1
  • 5
  • 9
  • 8
    Not exactly. Your code is synchronous in a sense that nothing happens until you get a result. However underneath, you probably gave up the thread you were running on until the async method returned, then got assigned another thread to continue executing. – Roman Jan 14 '13 at 16:31
  • 2
    it is but with async you can do another async at the same time and then await the 2, with sync this is not possible – ratchet freak Jan 14 '13 at 16:32
  • Here's an article (http://tomasp.net/blog/async-compilation-internals.aspx) discussing some of the under-the-hood of async in C# -- it's part of a series covering asynchronous programming in C# and F#. – paul Jan 14 '13 at 16:49
  • @ratchetfreak: Yes, that goes without saying if you're doing multiple calls. – Mrchief Jan 14 '13 at 19:09
  • @R0MANARMY: *If* your app is doing other things, then yes and async + await enables that. Akim says it best! But imagine the code not being in button_click handler, or any such event handler for that matter. If someone blindly copies the code (async+await lines), to any method, it can lead to fals impression that your code is async but in effect may not be. – Mrchief Jan 14 '13 at 19:12
  • @Mrchief: Yes, Akim said what I was trying to say, but better. – Roman Jan 14 '13 at 19:16

5 Answers5

49

No, async + await != sync, because of continuation

From MSDN 'Asynchronous Programming with Async and Await (C# and Visual Basic)'

Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

For example async execution will not block UI thread, and Some TextBox.Text will be updated after download has finished

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}
Akim
  • 999
  • 7
  • 16
  • 1
    Very nicely said! – Mrchief Jan 14 '13 at 19:13
  • 1
    Could you explain in more detail. Are you saying... that without this... you would not be able to interact with the UI... as this would be on the main thread. So does this mean that this only become applicable in a application type program apposed to web where interaction is separate from the web server thread. So in a nut shell this only become important i.e. not sync* when your main thread is the running thread. Wouldn't this create unexpected behavior, i.e. in a App(1 main thread) two buttons clicked.. but you should be able to click the 1 without the first completing? – Seabizkit Dec 07 '16 at 09:38
  • What about `Console.WriteLine(await GetStringOverNetwork());`? What if you need the output of the asynchronous invocation? Would the program block on first access, even if the thread could potentially continue execution? – Andrew Nov 05 '18 at 04:01
  • @Seabizkit **whatever** calls you `await + async` has the opportunity to do other stuff in the mean time. If you should only be able to click one button at a time, then you need to disable the other button before the first `await` – Caleth Jul 30 '20 at 09:24
  • @Caleth this was posted in 2016, i have a much much better understanding now. reading stuff like this now, in retrospect is difficult as i don't know what i did and didn't know then... but have it all down like a boss in the +-4 years since ;-) – Seabizkit Jul 30 '20 at 10:03
12

No it's not the same.

Your async code block is waiting for the await call to return to continue, however the rest of your application isn't waiting and can still continue like normal.

In contrast, a synchronous call would make your entire application or thread wait until the code finished executing to continue on with anything else.

Rachel
  • 23,979
  • 16
  • 91
  • 159
  • couldn't the sync call be implemented as async+await? – ratchet freak Jan 14 '13 at 16:35
  • @ratchetfreak I think there's some overhead to setting up await/async, so I don't think you'd want to code your entire application with it. I only use it for executing potentially long-running blocks of code so it doesn't lock up my applications. :) – Rachel Jan 14 '13 at 16:39
7

Please allow me to clarify things in regards to async/await.

When await is encountered the underlying state machine allows control to be returned immediately. Then, when the awaited call is completed, the underlying state machine allows execution to resume at the line after the awaited call.

Therefore, the async block is not blocked nor is it waiting for the awaited call to finish; Control is returned immediately when the await command is encountered.

The underlying state machine is part of the "magic" behind the use of async/await that is not disused and missed.

Cedric Harris
  • 71
  • 1
  • 1
7

I stumbled on this with the same question in mind, yet after reading the responses the question seems to linger, confused by references to "magic under the hood".

From the above-mentioned Asynchronous Programming :

  • The async keyword turns a method into an async method, which allows you to use the await keyword in its body.
  • When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete.
  • await can only be used inside an async method.

Does the context that encounters await get blocked?

  • Yes. That's essentially a local sync barrier to maintain a known state in the context of the execution; except that other contexts, if any, are not joined.

Does the rest of the application block at the await?

  • It depends on how your application is written. If it's a series of dependent awaited tasks launched sequentially in the same context (see: Trying to understand some async/await behavior)

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

    this way each await would block spawning of the next one.

    On the other hand, the same dependent tasks launched in parallel would execute in parallel and the context would only block at the resp. 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
    

    In general, the await yields execution to the outer context, from where the current context is called. However, if the outer context itself is awaiting for the current, then it's like a sequential awaits in the same context.

So, to reap the async benefits, one needs to design the application to run several parallel contexts (UI, data-client etc.), then await in one context yields execution to other contexts, so the whole application would not block on an individual await.

oversynched
  • 71
  • 1
  • 1
0

async + await don't just make an asynchronous call and wait for the result to be delivered, that would indeed be synchronous. That would happen if you created a semaphore, launched a new pthread for example that signals the semaphore when it is finished, and then wait on the semaphore. But async + await as part of the language is different.

What it does is basically creating a new thread to run the "async" task, passes the "await" code to it as a continuation (which is comparable to a "clever" function pointer),and when the task finished, it calls the "await" code. In other languages, like Objective-C or Swift, that's actually how you achieve the same effect. And all that is asynchronous.

gnasher729
  • 42,090
  • 4
  • 59
  • 119