Why use async when I have to use await?

10,311

Solution 1

If I use await here, what's the point of the asynchronous method?

await does not block thread. MyMethod2 will run synchronously until it reaches await expression. Then MyMethod2 will be suspended until awaited task (MyMethod) is complete. While MyMethod is not completed control will return to caller of MyMethod2. That's the point of await - caller will continue doing it's job.

Doesn't it make the async useless that VS is telling me to call await?

async is just a flag which means 'somewhere in the method you have one or more await'.

Does that not defeat the purpose of offloading a task to a thread without waiting for it to finish?

As described above, you don't have to wait for task to finish. Nothing is blocked here.

NOTE: To follow framework naming standards I suggest you to add Async suffix to asynchronous method names.

Solution 2

Does that not defeat the purpose of offloading a task to a thread without waiting for it to finish?

Yes, of course. But that's not the purpose of await/async. The purpose is to allow you to write synchronous code that uses asynchronous operations without wasting threads, or more generally, to give the caller a measure of control over the more or less asynchronous operations.

The basic idea is that as long as you use await and async properly, the whole operation will appear to be synchronous. This is usually a good thing, because most of the things you do are synchronous - say, you don't want to create a user before you request the user name. So you'd do something like this:

var name = await GetNameAsync();
var user = await RemoteService.CreateUserAsync(name);

The two operations are synchronous with respect to each other; the second doesn't (and cannot!) happen before the first. But they aren't (necessarily) synchronous with respect to their caller. A typical example is a Windows Forms application. Imagine you have a button, and the click handler contains the code above - all the code runs on the UI thread, but at the same time, while you're awaiting, the UI thread is free to do other tasks (similar to using Application.DoEvents until the operation completes).

Synchronous code is easier to write and understand, so this allows you to get most of the benefits of asynchronous operations without making your code harder to understand. And you don't lose the ability to do things asynchronously, since Task itself is just a promise, and you don't always have to await it right away. Imagine that GetNameAsync takes a lot of time, but at the same time, you have some CPU work to do before it's done:

var nameTask = GetNameAsync();

for (int i = 0; i < 100; i++) Thread.Sleep(100); // Important busy-work!

var name = await nameTask;
var user = await RemoteService.CreateUserAsync(name);

And now your code is still beautifuly synchronous - await is the synchronization point - while you can do other things in parallel with the asynchronous operations. Another typical example would be firing off multiple asynchronous requests in parallel but keeping the code synchronous with the completion of all of the requests:

var tasks = urls.Select(i => httpClient.GetAsync(i)).ToArray();

await Task.WhenAll(tasks);

The tasks are asynchronous in respect to each other, but not their caller, which is still beautifuly synchronous.

I've made a (incomplete) networking sample that uses await in just this way. The basic idea is that while most of the code is logically synchronous (there's a protocol to be followed - ask for login->verify login->read loop...; you can even see the part where multiple tasks are awaited in parallel), you only use a thread when you actually have CPU work to do. Await makes this almost trivial - doing the same thing with continuations or the old Begin/End async model would be much more painful, especially with respect to error handling. Await makes it look very clean.

Solution 3

An async method is not automatically executed on a different thread. Actually, the opposite is true: an async method is always executed in the calling thread. async means that this is a method that can yield to an asynchronous operation. That means it can return control to the caller while waiting for the other execution to complete. So asnync methods are a way to wait for other asynchronoous operations.

Since you are doing nothing to wait for in MyMethod2, async makes no sense here, so your compiler warns you.

Interestingly, the team that implemented async methods has acknowledged that marking a method async is not really necessary, since it would be enough to just use await in the method body for the compiler to recognize it as async. The requirement of using the async keyword has been added to avoid breaking changes to existing code that uses await as a variable name.

Share:
10,311
sham
Author by

sham

Updated on June 25, 2022

Comments

  • sham
    sham almost 2 years

    I've been stuck on this question for a while and haven't really found any useful clarification as to why this is.

    If I have an async method like:

    public async Task<bool> MyMethod()
    {
        // Some logic
        return true;
    }
    
    public async void MyMethod2()
    {
        var status = MyMethod(); // Visual studio green lines this and recommends using await
    }
    

    If I use await here, what's the point of the asynchronous method? Doesn't it make the async useless that VS is telling me to call await? Does that not defeat the purpose of offloading a task to a thread without waiting for it to finish?

  • sham
    sham about 7 years
    So if I don't need to wait for a task to finish, I can ignore the use of async - await? I can just create MyMethod2() to be a void and still call MyMethod() which will still run the task on another thread?
  • Sergey Berezovskiy
    Sergey Berezovskiy about 7 years
    @Toby making asynchronous methods return void is a bad practice - because you will never know whether async operation completed successfully or was completed at all. You should return Task in such cases. Here is good article on async-await pattern in C# and the way it works msdn.microsoft.com/en-us/library/…
  • Henk Holterman
    Henk Holterman about 7 years
    async void is dis-advised unless it's used for an event handler.
  • Craig
    Craig about 6 years
    'you don't always have to await it right away' - I think this is the core of the explanation. Unfortunately almost all the code samples we see do call await right away and so lead to this confusion. Your nameTask example illustrates the concept well.
  • Johan Maes
    Johan Maes about 5 years
    Excellent explanation but the question remains: if the call to a method is always awaited right away, does it still make sense to make the method async?
  • Luaan
    Luaan about 5 years
    @JohanMaes Of course, the main point of await is still that it allows you to forfeit your CPU time in an efficient manner. The only real case where you might want not to use an async method is if it only has one await at the very end (so you can just return the result of that instead), and even then it's something to consider because debugging becomes a bit different. If you have multiple operations in a sequence, await still allows you to chain them in an easy manner (rather than having to deal with continuations).
  • David
    David about 4 years
    Even though control is returned to the caller of MyMethod2, MyMethod2 in the calling method has an await keyword and the code below is placed in a continuation block and awaiting completion of MyMethod2.
  • Bamdad
    Bamdad about 3 years
    @JohanMaes You can see in the second code of block that it's not awaited right away. Sometimes you need to do some work in the caller scope in parallel with the tasks. Well explained, thanks.