TostMaster
TostMaster

Reputation: 174

Can synchronous methods continue their execution before an asynchronous sub-call has completed?

I have issues understanding a detail about async programming in C#.

Lets say I have a common async method, that has a few await statements in it. Lets say I have another method, which is not async, but calls the first method.

public void DoSomething(){
    DoSomethingAsync()
    ...
}

public async Task DoSomethingAsync(){
    ...
    await ...
    ...
}

I know i could just use Wait() or some other synchronization technique, but i dont just want to throw stuff at problems without knowing what happens.

Will DoSomething continue execution before DoSomethingAsync is completed? I know that this would happen if DoSomething were to be declared async, but it isn't.

Or to be more general: Can synchronous methods continue their execution before an asynchronous sub-call has completed?

Upvotes: 0

Views: 723

Answers (4)

Stephen Cleary
Stephen Cleary

Reputation: 457147

Can synchronous methods continue their execution before an asynchronous sub-call has completed?

As others have noted, the answer to this is "yes".

All asynchronous methods begin executing synchronously. They return a task that represents the completion of that asynchronous method. The task is completed when the asynchronous method is completed. If the asynchronous method returns a result, then the task is completed with a result value. If the asynchronous method throws an exception, then the task is completed with an exception (i.e., faulted).

However, this also means that there is are some problems with the code you've posted. Specifically, it's doing a kind of "fire and forget", and that's dangerous.

This code is just ignoring the task returned from DoSomethingAsync:

public void DoSomethingElse(){
    DoSomethingAsync()
    ...
}

So that means it's saying "start doing something" and it's also saying "I don't care if or when that 'something' completes, and I don't care if it throws an exception". There are a couple problems with this: 1) since your app doesn't know when "something" completes, it can't know when it's safe to shut down, and 2) your app won't be notified if "something" fails.

In the vast, vast majority of scenarios, that means the app has bugs. "Fire and forget" is only appropriate when doing an operation where it doesn't actually matter if the operation fails or isn't even completed. There are very few operations where this is the case.

This is why - as a general rule - tasks should eventually be awaited. If you want to start an operation and then do other things and then await that operation to complete, that's not uncommon:

public async Task DoSomethingElseAsync() {
  var task = DoSomethingAsync();
  ... // other synchronous/asynchronous work.
  await task; // asynchronously wait for DoSomethingAsync to complete,
              // and propagate any exceptions.
}

Upvotes: 1

joe
joe

Reputation: 1308

TL;DR It continues

Can synchronous methods continue their execution before an asynchronous sub-call has completed?

Of course it can, if a synchronous method has to wait an asynchronous method to finish, what's the purpose of going asynchronous? (It can wait as well, depending on what you want to achieve)

async/await pattern in your code will create a state machine that can be recovered later. By the time your code hits await, the task you await on will be pushed to the task scheduler and might be executed in some threadpool thread. The async method returns and let the synchronous method continue.

When the task is finished, the state machine recovers the context, and everything in DoSomethingAsync after await continues. On which thread it would run? This depends on if you set ConfigureAwait and the threading model of your program. For example, for a WPF application, by default, it comes back to the main thread, and that's why wait + await can lead to deadlocks.

Upvotes: 1

Darkwing
Darkwing

Reputation: 7595

In the absence of the await operator this method will behave as if this call is not awaited, execution of the current method continues before the call is completed

The compiler will warn you:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs4014?f1url=%3FappId%3Droslyn%26k%3Dk(CS4014)

Upvotes: 1

Klamsi
Klamsi

Reputation: 906

What happens is:

DoSomething calls DoSomethingAsync. Then a synchronous! order starts until the first "await" is reached. With this await, the DoSomethingAsync returns a Task object the has status "not finished yet". But as you do not assign this return value and also do nothing else special your DoSomething continues.

Upvotes: 1

Related Questions