Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I await my asyncs?

We're currently refactoring sections of our project to be async up and down, yay!

Due to our different understanding, me and a colleague (let's call him Jim), have differing opinions about how our async/await code will execute, and which way to write it.

Here is the example method Jim wrote:

public async Task<HouseModel> GetHouseModel(Guid houseId) {     House house = await _houseService.GetHouse(houseId);      Task<IEnumerable<Furniture>> furniture = _furnitureService.GetFurnitureForHouse(house);      Task<IEnumerable<Appliances>> appliances = _applianceService.GetAppliancesForHouse(house);      return _houseModelFactory.MakeHouseModel(await furniture, await appliances); } 

And the example of how I would write it:

public async Task<HouseModel> GetHouseModel(Guid houseId) {     House house = await _houseService.GetHouse(houseId);      IEnumerable<Furniture> furniture = await _furnitureService.GetFurnitureForHouse(house);      IEnumerable<Appliances> appliances = await _applianceService.GetAppliancesForHouse(house);      return _houseModelFactory.MakeHouseModel(furniture, appliances); } 

My understanding is: because the methods in both the furniture and appliance services in the above require House, they will wait for House to be available before continuing. Then, both methods that need House will run, but the second method (GetAppliancesForHouse) will not wait for the first to finish before starting.

Jim's understanding is: that we should await both methods only when they are needed. So that they will both run parallel to each other. He thinks that doing it my way will result in the second method waiting for the first, i.e.: GetAppliancesForHouse waiting for GetFurnitureForHouse.

Are any of these understandings correct? Or have we just been making it up as we go along? When should we await?

like image 964
Jack Pettinger Avatar asked Aug 22 '18 12:08

Jack Pettinger


People also ask

When should you use async await?

Async/Await makes it easier to write promises. The keyword 'async' before a function makes the function return a promise, always. And the keyword await is used inside async functions, which makes the program wait until the Promise resolves.

Should you always await async methods?

If a method is declared async, make sure there is an await! If your code does not have an await in its body, the compiler will generate a warning but the state machine will be created nevertheless, adding unnecessary overhead for an operation that will actually never yield.

Is it OK to not await async?

If you forget to use await while calling an async function, the function starts executing. This means that await is not required for executing the function. The async function will return a promise, which you can use later.

Does async await improve performance?

C# Language Async-Await Async/await will only improve performance if it allows the machine to do additional work.


2 Answers

Neither of you is correct, see the answer by @erndob for the reasons. However, one of the questions is not answered:

When should we await?

  • Do you want the work to be done sequentially? Use your way.
  • Do you want the work to be done in parallel? Use Jim's way.

Note: Jim's way will not actually run in parallel if the Task Scheduler used is unable to run both Tasks at the same time, for example, due to lack of system resources (thanks @AdamSimon).

like image 28
Camilo Terevinto Avatar answered Oct 11 '22 10:10

Camilo Terevinto


My understanding is: because the methods in both the furniture and appliance services in the above require House, they will wait for House to be available before continuing.

Your understanding is wrong. The methods that require House, they are not waiting for you to get House because you need it. They don't resolve their dependencies and when to wait for code or not on their own. The code waits to get Houses because you have await before it. It's not aware of what's going to happen next.

Then, both methods that need House will run, but the second method (GetAppliancesForHouse) will not wait for the first to finish before starting.

Similarly, the GetAppliancesForHouse won't have its own understanding if it should wait or not based on the dependencies. GetAppliancesForHouse won't run, because your code says to await GetFurnitureForHouse before it first. Your code will always run sequentially.

Jim's understanding is: that we should await both methods only when they are needed. So that they will both run parallel to each other.

That's generally true. As others have pointed out, the code still might run not in parallel depending on other factors. Also, there might be legitimate reasons to not want to run code in parallel.

He thinks that doing it my way will result in the second method waiting for the first, ie: GetAppliancesForHouse waiting for GetFurnitureForHouse.

He's right.

To see what happens exactly, you can put breakpoints and see what happens after each line. In Jims case, after going from Furniture to Appliances, furniture variable won't have the value yet, it's still a task, but you are already in the next line.

With your case, going to Appliances line, you will see that Furniture already has the value, since it waited for it.

like image 102
Erndob Avatar answered Oct 11 '22 11:10

Erndob