7

Consider the following code:

public static void Run() {
    DoStuffAsync();
}

public static async Task DoStuffAsync() {
     PerformCalc();
     await DoLongTaskAsync();
     PerformAnotherCalc();
}

Let's say I call Run(). I have a few questions regarding behaviour:

  1. Will PerformCalc() be called synchronously on the same thread as the one that called Run()?
  2. Will DoLongTaskAsync() be called asynchronously or synchronously? In other words, will/can PerformAnotherCalc() be called before DoLongTaskAsync() has finished?
  3. Subsequently, can the DoStuffAsync() method return before execution of DoLongAsyncTask() has completed?
2
  • 1
    1. Yes. 2. No. 3. It can (or will provided that DoLongTaskAsync is indeed asynchronous and returns an uncomplete task) return but not complete. Commented Aug 15, 2019 at 12:08
  • 1
    You can write a small test application and see for yourself. Calling a method that has async in its signature without await calling, is the same as if it didn't have async. Like any regular c# method. Commented Aug 15, 2019 at 12:27

4 Answers 4

11

Async methods always start running synchronously. The magic happens at await, but only when await is given a Task that has not completed.

In your example, this is what will happen when you call Run():

  1. Jump to DoStuffAsync()
  2. Jump to PerformCalc()
  3. Jump to DoLongTaskAsync()
  4. If DoLongTaskAsync() is a truly asynchronous operation and returns an incomplete Task, then await does its job and DoStuffAsync() returns an incomplete Task to Run().
  5. Since the task is not awaited, Run() completes.
  6. When DoLongTaskAsync() completes, DoStuffAsync() resumes, and jumps to PerformAnotherCalc().

All of that can happen on the same thread.

So to answer your questions:

  1. Yes. If it is an async method, it might end up going out and doing things on other threads. But it will start synchronously on the same thread.
  2. DoLongTaskAsync() will be called asynchronously, but PerformAnotherCalc() will not be called before DoLongTaskAsync() finishes, because you used await.
  3. Yes. This is how await works. It will return an incomplete Task (that is, only if DoLongTaskAsync() is truly asynchronous and returns an incomplete Task). Then once DoLongTaskAsync() finishes, execution of DoStuffAsync() resumes where it left off.
Sign up to request clarification or add additional context in comments.

1 Comment

Good answer. A small note: Async methods always start running synchronously relative to the caller. This is important because if the caller is already running asynchronously, it will be synchronous to the caller but not necessarily to the caller that called the caller. Pretty sure this is what you meant but may help avoiding confusion.
3
  1. Will PerformCalc() be called synchronously on the same thread as the one that called Run()?

Yes.

  1. Will DoLongTaskAsync() be called asynchronously or synchronously? In other words, will PerformAnotherCalc() be called before DoLongTaskAsync() has finished?

It will be called synchronously, but it may return a Task before the "Long Task" operation has finished. Either way, the Task it returns is awaited, so PerformAnotherCalc will not be called until the Task returned from DoLongTaskAsync completes.

  1. Subsequently, can the DoStuffAsync() method return before execution of DoLongAsyncTask() has completed?

The DoStuffAsync method will return when it hits the first await (iff the Task being awaited is pending). That's how async methods work -- they run synchronously up until the first await of a Task which is pending, and then they return a Task which will complete when the whole method has executed.

If might be that DoLongTaskAsync returns a Task which has already completed: in that case, DoStuffAsync won't return until PerformAnotherCalc has returned. If DoLongTaskAsync returns a Task which is still pending, then DoStuffAsync will return at that point, and it will return a Task which completes once the Task returned from DoLongTaskAsync has completed, and PerformAnotherCalc has returned.

Comments

1
  1. Yes
  2. No
  3. Yes

Put otherwise, if you consider those methods:

public static void Run1() {
    DoStuffAsync();
    Console.WriteLine("Done");
}

public static async Task Run2() {
    await DoStuffAsync();
    Console.WriteLine("Done");
}

public static async Task DoStuffAsync() {
     PerformCalc();
     await DoLongTaskAsync();
     PerformAnotherCalc();
}

In Run2, you are guaranteed that "Done" will be displayed after PerformAnotherCalc. In Run1, "Done" will be displayed after PerformCalc but before PerformAnotherCalc (assuming that DoLongTaskAsync is actually asynchronous, which depends of its implementation).

2 Comments

You might check the comment below the code. Looks like you mix up his example and yours
@JeroenvanLangen I was mixing both examples yes. Added the missing bit to my answer to make it easier to understand
-1

All calls are synchronous. It's the await that can be asynchronous if the returned awaitable is not complete.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.