Usually, you want to write asynchronous code for 2 different types of purposes or needs:
I/O bound code. This is when you want to do an input/output operation, particularly, downloading big resource from network, reading a huge file or accessing a database resouce. In this case, you use the
awaitkeyword on an async method that returns a
CPU bound code. This is when you want to do a heavy in-app calculation, such as calculating and displaying the remaining distance to reach the finish line of a car racing game. Image what will happen if the was done synchronously and the UI was blocked while calculating the remaining distance when the car is moving?! Therefore, In the CPU bound case, you use the await keyword on an async method that will be running on a background thread using the method
In both scenarios, your application's UI or service's responsiveness or running state should not be blocked or affected.
For every async method, the .Net framework will create a state machine to keep track of the calls and what should be done after the awaitable task has complete. Check this comprehensive in-depth article about async / await compilation and state machines, Also if you want to learn more about Async and what happens behind the scenes of
Task<T>, read Async in Depth.