3

If you have an async function:

public async Task DoWork()
{
    await DoSomeWorkAsync();
    await DoSomeMoreWorkAsync();
}

Now the first await prevents the method blocking the calling context, so is useful.

But after DoSomeWorkAsync has completed, the method is anyways running in a different context, since in the compiler its been converted to something like Task.ContinueWith(await DoSomeMoreWorkAsync()).

So is their any purpose to awaiting DoSomeMoreWorkAsync/running it async? Are there any disadvantages? Should I use a non-async version of DoSomeMoreWorkAsync if it exists?

ie. would this be disadvantageous in any way:

public async Task DoWork()
{
    await DoSomeWorkAsync();
    DoSomeMoreWork();
}

EDIT: This is not the same question as Multiple Awaits in a single method. That asks what happens. I'm asking is there any advantage to that happening.

FaizanHussainRabbani
  • 3,256
  • 3
  • 26
  • 46
Yair Halberstadt
  • 5,733
  • 28
  • 60
  • @HimBromBeere: This is not the same as the existing question. That asks what happens. I'm asking is there any advantage to that happening. I looked at that question before asking this. – Yair Halberstadt Mar 05 '18 at 11:07
  • Well, the point obviously is that you have *multiple* steps your asnyc method should execute. For your calling member those steps are hidden, as it doesn´t know anything about the internals of your method. However for the latter it´s just a flow of processes one after the other. So for the asnyc method you have some sub-tasks that should execute *synchronously*, which means: first execute `DoSometWork`, and when it´s finished execute `DoSomeMoreWork`. Only if the latter is finished, the whole task returned by the asny method is completed. – MakePeaceGreatAgain Mar 05 '18 at 11:15

2 Answers2

8

It seems you are thinking that avoiding blocking of the caller is the only purpose of async methods, that's not so. Async methods are usually async because at some point they perform asynchronous IO, such as working with files, databases, web requests and so on (or calling other async methods that do this).

When real async IO is in progress, no thread in your application is busy waiting for it to complete (well, there is thread, but it's one for the whole application, not per specific IO task).

That means even IF await DoSomeMoreWorkAsync executes on some thread pool thread - when at some point it will reach async IO - this thread pool thread will be released and will be available for more useful work.

On the other hand, if you will use synchronous version instead (DoSomeMoreWork) - it will block current thread pool thread for the whole duration, including IO, so this thread will not be available for useful work.

Releasing threads whenever possible might be quite important in applications using them heavily, such as web applications.

In addition to the above, this statement

But after DoSomeWorkAsync has completed, the method is anyways running in a different context

is not always true. For example in UI application, if you call DoWork from UI thread, continuation (await DoSomeMoreWorkAsync()) will also be executed on UI thread. That means if you replace it with synchronous version - UI thread will freeze for the duration of it.

Evk
  • 98,527
  • 8
  • 141
  • 191
4

So is there any purpose to awaiting DoSomeMoreWorkAsync?

Well, if it is asynchronous, then you absolutely want to await it so your DoWork method does not complete before that “some more work” is also done. If it was asynchronous, and you did not await it, it would essentially be fire and forget which is very rarely what you want.

So is there any purpose to running it async?

That depends on the function. You do not make methods asynchronous because you want to call them asynchronous. Methods are asynchronous because they perform asynchronous tasks.

If the method is doing purely CPU bound work which won’t run asynchronous anyway, then there is no reason in making it asynchronous, no. Actually, leave it synchronous to clearly communicate to the callers that there is no asynchronous process going on.

But if it is something that benefits from being asynchronous, e.g. because it does asynchronous network or I/O calls, then it probably should be asynchronous. And then you should also await it.

Are there any disadvantages?

There are always disadvantages. Running asynchronous code is more expensive than running synchronous code because there is a non-trivial amount of overhead being generated and called (which we luckily don’t have to deal with when writing async code). But that overhead does not really matter when looking at the advantages real asynchronous code can give you.

So you really shouldn’t use this to decide whether to make something asynchronous or not. Think about what the method does and how it does it, and then decide whether that process is synchronous or asynchronous.

poke
  • 369,085
  • 72
  • 557
  • 602
  • Many IO libraries provide both async and non-async versions of their calls. So given this method is running asynchronously anyways, should I use the non-async version to avoid the overhead? – Yair Halberstadt Mar 05 '18 at 11:23
  • 2
    Again, that depends on what the function is doing, not how you want to call it. If it’s a process that can benefit from being asynchronous, then you’re much better off having it asynchronous. And libraries that offer both async and sync calls often just block on the asynchronous call to make it synchronous. – poke Mar 05 '18 at 11:36