Friday 15 May 2020

Asyn & await in C# with example

When using async and await the compiler generates a state machine in the background.

Here's an example on which I hope I can explain some of the high-level details that are going on:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

OK, so what happens here:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); starts executing LongRunningOperation

  2. Independent work is done on let's assume the Main Thread (Thread ID = 1) then await longRunningTask is reached.

    Now, if the longRunningTask hasn't finished and it is still running, MyMethodAsync() will return to its calling method, thus the main thread doesn't get blocked. When the longRunningTask is done then a thread from the ThreadPool (can be any thread) will return to MyMethodAsync() in its previous context and continue execution (in this case printing the result to the console).

A second case would be that the longRunningTask has already finished its execution and the result is available. When reaching the await longRunningTask we already have the result so the code will continue executing on the very same thread. (in this case printing result to console). Of course this is not the case for the above example, where there's a Task.Delay(1000) involved.


An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off. 

--------------

For fastest learning..

  • Understand method execution flow(with a diagram): 3 mins

  • Question introspection (learning sake): 1 min

  • Quickly get through syntax sugar: 5 mins

  • Share the confusion of a developer : 5 mins

  • Problem: Quickly change a real-world implementation of normal code to Async code: 2 mins

  • Where to Next?

Understand method execution flow(with a diagram): 3 mins

In this image, just focus on #6 (nothing more) enter image description here

At #6 step: Execution stopped here as it has run out of work. To continue it needs a result from getStringTask(kind of a function). Therefore, it uses an await operator to suspend its progress and give control back(yield) to the caller(of this method we are in). The actual call to getStringTask was made earlier in #2. At #2 a promise was made to return a string result. But when will it return the result? Should we(#1:AccessTheWebAsync) make a 2nd call again? Who gets the result, #2(calling statement) or #6(awaiting statement)

The external caller of AccessTheWebAsync() also is waiting now. So caller waiting for AccessTheWebAsync, and AccessTheWebAsync is waiting for GetStringAsync at the moment. Interesting thing is AccessTheWebAsync did some work before waiting(#4) perhaps to save time from waiting. The same freedom to multitask is also available for the external caller(all callers in the chain) and this is the biggest plus of this 'async' thingy! You feel like it is synchronous..or normal but it is not.

Remember, the method was already returned(#2), it cannot return again(no second time). So how will the caller know? It is all about Tasks! Task was passed. Task was waited for (not method, not value). Value will be set in Task. Task status will be set to complete. Caller just monitors Task(#6). So 6# is the answer to where/who gets the result.

No comments:

Post a Comment

Baisic Useful Git Commands

  Pushing a fresh repository Create a fresh repository(Any cloud repository). Open terminal (for mac ) and command (windows) and type the be...