23

So here is the scenario:

static async void Main(string[] args) 
{
    await AnAsyncMethod();
}

private static async task<bool> AnAsyncMethod()
{
    var x = await someAsyncMethod();
    var y = await someOtherAsyncMethod();

    return x == y;
}

Is "someAsyncMethod" and "someOtherAsyncMethod" running synchronously because we are using await, or are they both running asynchronously in the order that they are being executed?

UPDATE

Given the answer below stating that the awaited async methods will run sequentially, what would be the purpose of making those method calls asynchronous in the first place if we are just going to stop execution and wait the those method's return values? I have seen native apps in the past use await/async as a means to free up the UI thread, but are there any other reasons why this design would be desirable?

mdlars
  • 909
  • 10
  • 16
  • 5
    small sidenote `Main` cannot use `await` as its not itself marked as `async` – Jamiec Sep 09 '15 at 14:28
  • on top of @Jamiec comment, if you create another another class and put that async method in there, you can then call in your Main method, `new SomeClass().AnAsyncMethod.Wait();` and it will happen asynchronously – Callum Linington Sep 09 '15 at 14:30
  • 1
    My understanding is that someAsyncMethod would entirely finish before someOtherAsyncMethod would start. – Biscuits Sep 09 '15 at 14:32
  • What's the difference between "synchronously" and "asynchronously in the order that they are being executed"? – Luaan Sep 09 '15 at 14:36
  • I've improved my answer to address your follow-up question. – dcastro Sep 09 '15 at 14:43
  • 2
    @Biscuits Not even that - await has nothing to do with how the methods (or their tasks) are executed; it simply handles what happens when the tasks are completed. I can await an enumerable if I want just by adding a simple extension method. It has nothing to do with threads (and only a little to do with tasks, really). – Luaan Sep 09 '15 at 14:44
  • 1
    @dcastro thanks for the in-depth follow up! – mdlars Sep 09 '15 at 14:45
  • @CallumLinington Calling `Wait()` and not awaiting will not make it happen asynchronously... `Wait()` is blocking. – Jamie Rees Sep 09 '15 at 15:14
  • 2
    `what would be the purpose of making those method calls asynchronous in the first place` I wish more people were asking that... Maybe you'll like my standard posts on when to use async IO and why: http://stackoverflow.com/a/25087273/122718 Why does the EF 6 tutorial use asychronous calls? http://stackoverflow.com/a/12796711/122718 Should we switch to use async I/O by default? – usr Sep 09 '15 at 15:34
  • @JamieRees Yeah that's what I meant. – Callum Linington Sep 10 '15 at 07:24

1 Answers1

28

They are running asynchronously, but sequentially. someOtherAsyncMethod will not be invoked until someAsyncMethod finishes.

If you want to run them in parallel, you have several options

var taskA = MethodA();
var taskB = MethodB();

var a = await taskA;
var b = await taskB;

// or

var results = await Task.WhenAll(MethodA(), MethodB());

Follow-up question:

I have seen native apps in the past use await/async as a means to free up the UI thread, but are there any other reasons why this design would be desirable?

In an ASP.NET application, you'll want to use this to allow the current thread to go back to the threadpool and serve other incoming requests, while MethodA/MethodB are running - IF these methods are doing true async I/O. That's basically the only reason why you'd do this in an ASP.NET app.

You might also want to read Stephen Cleary's:

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • 2
    Note that you can't use Task.WhenAll with mutliple EF calls on the same context. That one has certainly bitten me before. – Keith Rousseau Sep 09 '15 at 14:31
  • 4
    And not just in ASP.NET - in any multi-user server application, you'll benefit from keeping your thread count low. Every thread means non-negligible memory and CPU usage - if you have 4000 threads, you lost 4 GiB of memory (hopefully non-commited, at least) just on the default thread stacks. And since you only ever really as many threads as you have CPU cores, give or take, this is an utterly unnecessary waste. This is especially true in a 32-bit application, where even the amount of *virtual* memory is limited. – Luaan Sep 09 '15 at 14:49
  • @Luaan Thanks for the addendum, very useful! – dcastro Sep 09 '15 at 15:00
  • 2
    @Biscuits Option 1 would kick off both tasks, and *then* await them. It doesn't matter whether you wait `a` then `b`, or `b` then `a`. What matters is that you kick off *both* before you await *either*. – dcastro Sep 09 '15 at 15:03
  • @dcastro Thanks! I just had a pretty spectacular eureka moment. Upvote! – Biscuits Sep 09 '15 at 15:11
  • 2
    @Biscuits The confusion is understandable, and stems from the fact that those expressions are not [referentially transparent](http://programmers.stackexchange.com/a/254308/1013080). That is, replacing `taskA` with `MethodA()` changes the *meaning* of the program. – dcastro Sep 09 '15 at 20:02
  • FYI, I ran a test in VS, and can see that when going into the async method under and await, it has the same thread ID. It also has the same thread ID after the await. This implies that it did, in fact, run the method synchronously. – Worthy7 Nov 16 '17 at 05:54