How Async and Await Works

How Async and Await works

I have an async intro on my blog that you may find helpful.

This code:

int result = await LongRunningOperation();

is essentially the same as this code:

Task<int> resultTask = LongRunningOperation();
int result = await resultTask;

So, yes, LongRunningOperation is invoked directly by that method.

When the await operator is passed an already-completed task, it will extract the result and continue executing the method (synchronously).

When the await operator is passed an incomplete task (e.g., the task returned by LongRunningOperation will not be complete), then by default await will capture the current context and return an incomplete task from the method.

Later, when the await task completes, the remainder of the method is scheduled to run in that context.

This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. If you're running this in a Console app, then the context is usually the thread pool context, so the async method will resume executing on a thread pool thread. However, if you execute the same method on a UI thread, then the context is a UI context and the async method will resume executing on the UI thread.

How does javascript async/await actually work?

You have to read the quoted part slightly differently:

An async function can contain an await expression that pauses the execution of the async function

Just the async function itself pauses execution, the function that called it goes on then.

If you think of a synchronous callstack, what happens is that the asynchronous functions context gets popped of, and stored somewhere else:

 stack: [init] -> [async] fun1 -> sleep -> setTimeout
// The promise gets returned from sleep
stack: [init] -> [async] fun1
// The async function gets popped of
stack: [init]
hidden: [async] fun1
// synchronous execution ends
stack: -
hidden: [async] fun1
// the timer triggers, the promise gets resolved
stack: setTimeout callback
hidden: [async] fun1
// synchronous execution ends
stack: -
hidden: [async] fun1
// the promise resolves, the async fun1 context gets moved onto the stack
stack: [async] fun1

It seems fun1 returns at the "await" line

Yes, exactly. In that moment it returns a promise, that resolves when the async function returns (after it continued execution somewhen).

And it seems I never get the return value of fun1("returnfromfun1").

You can get it when the promise resolves:

  fun1().then(result => console.log(result));

How do async/await/then really work in Dart?

The answer from Andrija is technically correct. However, I still had to think about it a lot until I was able to understand how it really works and this is why I will try to simplify things for anyone who might have the same question.

Suppose you have a dart program; obviously with a main(). Our program calls two functions; foo() and bar().

The function foo() does some asynchronous work, e.g. a network call:

Future<void> foo() async{
Stopwatch watch = Stopwatch();

watch.start();

await Future.delayed(Duration(seconds:1));

print(watch.elapsedMilliseconds);
}

And the function bar() is a normal function that executes some synchronous code:

void bar() {
print("Some synchronous code");
}

Now, suppose your main() looks like this:

void main() {
foo();
bar();
}

The main program starts and foo() is called -without an await in main()-, we hit the await in foo() and the program goes: "Oh! I'm not supposed to delay the rest of the execution in main(). I gotta register a callback to be executed when the async work is done and go continue the execution of main()". foo() is popped off of the call stack and bar() is then called and prints "Some synchronous work" and is also popped off of the call stack. In the meantime, the async work in foo() finishes and signals completion. This gets picked up by the event loop which goes back to executing the rest of the code in foo() (or the code in the callback if we use .then(); of course if the main thread is not busy.

And this is in simple words what happens. As Andrija suggested, the await blocks the rest of code execution in the same function; the rest of your program will run just fine. If we'd used an await in main() to a-wait for foo(), the execution in main() would've also been blocked until the async work in foo() is done which is not what I had initially thought.

My thinking was that the code in main() will also be delayed based on the await in foo(), which is not the case as we've seen.

How and when to use ‘async’ and ‘await’

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.

can anyone help me understand await/async implementation in c#

When compiling your code, you should have received warnings that gave you a hint what was wrong:

warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

An async method will run synchronously until it reaches the first await expression where the value it's awaiting isn't already completed.

In your case, all your async methods return completed tasks - Method1Async and Method2Async will simply run synchronously, then return a completed task, which means that CallMethodAsync will await those already-completed tasks, and itself complete synchronously.

If you add something like await Task.Yield() in Method1Async and Method2Async, then you'll see genuine asynchronous behavior: those methods will return incomplete tasks (when they reach Task.Yield) which means CallMethodAsync itself will return an incomplete tasks, etc.

Is my understanding of async/await, how it works and its benefits, correct?

That's pretty much correct.

A few notes though:

  • The thread that starts executing an async method is the caller's thread which may, or may not, be a ThreadPool thread.
  • If an await is reached, but the awaitable (usually Task) is already completed the thread will continue executing the rest of the method synchronously.
  • The thread that resumes running the method is usually a ThreadPool thread, but that depends on the SyncrhonizationContext and TaskScheduler.
  • The JIT isn't involved here (not more than usual). The compiler is the one that turns an async method into the state machine. You can see that with this TryRoslyn example.
  • It's true that async-await doesn't necessarily imply concurrency as it could be single threaded. However, it can still be concurrent even with just a single thread by starting and awaiting multiple asynchronous operations at the same time.
  • async-await and the TPL are not completely separate parts. async-await is built on top of the TPL. That's why it's called the Task-based Asynchronous Pattern.
  • While most truly asynchronous operations are I/O, not all are. You also usually delay asynchronously with Task.Delay or use asynchronous synchronization constructs like SemaphoreSlim.WaitAsync.

Async/Await in Javascript vs C#

I am not familiar with JavaScript but this statement:

Async/await makes your code look synchronous, and in a way it makes it
behave more synchronously. The await keyword blocks execution of all
the code that follows it until the promise fulfills, exactly as it
would with a synchronous operation.

Sounds pretty much applicable to C# async/await. For both cases your code looks like you execute it synchronously and your execution is sequential. Because in C# when you have code like this:

// ...
await FooAsync();
Console.WriteLine("Await has returned the execution");

It seems as if your execution thread were running FooAsync, and then, the same thread is calling Console.WriteLine. Whereas in reality when the execution thread hits await, it does lots of things behind the scene. Here's a good article about it. But in most of the cases,

When the await keyword is applied, it suspends the calling method and
yields control back to its caller until the awaited task is complete.

The thread that were executing your code will go about his business. And then proceed with Console.WriteLine when FooAsync is complete by another (or the same) thread.
This behavior is enormously helpful when you work with UI threads like in WPF or WinForms applications.
For example, FooAsync is a very heavy method. It does lots of calculations and takes a lot of time to complete. But you're running your code on UI and when a user hits a button, the underlying code is executed by the UI thread. So if you'll be running and waiting FooAsync synchronously like this:

FooAsync().Result;

Your UI would be "freezed" and the user would demise you.
So when you go

await FooAsync();

UI thread "asks" TaskScheduler to run FooAsync by whatever available thread. After the Task is completed, TaskScheduler tries to execute next line:

Console.WriteLine("Await has returned the execution");

by the UI thread again,

exactly as it would with a synchronous operation.

How does await async work in C#

MSDN explains everything.

I understand though that sometimes vanilla docs (particularly from MSDN) can be difficult to apply to your particular situation, so let's go over your points.

Question # 1: Is this assumption correct or the code below the await keyword is still executed?

The code below the "await" keyword will only be executed when the async call completes. In the meantime, since your method is marked "async", control will be returned to the caller of your method until your method completes.
From the MSDN link above:

Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();

// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;

I think the comments are quite explanatory.

Secondly suppose I called a service method async and need to return its result. The return statement is below the await keyword.

Question # 2: When is the return statement hit, after the async call has completed or before it?

After.

Question # 3: I want to use the result of that service call and async operation wont help cause I want the calling method to be hit when the result has been returned. I understand this can be done using the Result property which makes the call synchronus. But then what is the use of async in DB operations cause they are the ones that actually take 80% of the time in most apps.

Suppose you need to make three unrelated DB queries to complete your service, then perform a calculation based on the results, then finish. If you did this sequentially, you'd have to wait until each operation completes. If you use async calls, then C# will run the three queries in parallel and your service might finish much sooner.

Also, operations that return Task can be used as Futures. See MSDN on Futures where several patterns are discussed on how to parallelize work based on futures and merge the results.

If your service only needs one DB call then it will definitely be worse for you to call it async.

Question # 4: How can I use async with DB operations? Is it possible and recomended?

ADO.NET now includes async methods ReadAsync and NextResultAsync .

It is definitely possible, as for recommended this discussion is much more complete than I could write here.

Question # 5: In which scenraio will async operations be useful it seems that every api is just making async operations now without a reason? or did I miss the point of using async ops?

async operations are very useful to easily parallelize any long running operations without running into threading problems. If your method only does one thing, or a sequence of simple (fast) things, then yes it is useless to go async. However if you have more than one long running operations, it is far easier and less error prone to parallelize them via async than it is to do it managing threads.



Related Topics



Leave a reply



Submit