Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use async when I have to use await?

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?

like image 639
sham Avatar asked Mar 06 '17 11:03

sham


People also ask

Should await be always used with async?

Why does "await" always need an "async" ? This is because if you were able to put await in synchronous code, you would block the (main) thread. This was already possible to do before async and await keywords. You can simply resolve a promise.

Why should I use async?

Asynchronous loops are necessary when there is a large number of iterations involved or when the operations within the loop are complex. But for simple tasks like iterating through a small array, there is no reason to overcomplicate things by using a complex recursive function.

What happens if we dont use async await?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.


3 Answers

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.

like image 72
Luaan Avatar answered Oct 22 '22 17:10

Luaan


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.

like image 38
Sergey Berezovskiy Avatar answered Oct 22 '22 16:10

Sergey Berezovskiy


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.

like image 6
Sefe Avatar answered Oct 22 '22 16:10

Sefe