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?
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.
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.
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.
C# Language Async-Await Async/await will only improve performance if it allows the machine to do additional work.
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?
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With