How Async and Await works - c#

I am trying to understand how Async and Await works. How control travel in the program. Here is the code which I was trying to understand.
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
//indeed you can do independent to the int result work here
MySynchronousMethod();
//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation
{
await Task.Delay(5000); //5 seconds delay
return 1;
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
MyMethod();
}
When button click occur then MyMethod() will be called and from the MyMethod LongRunningOperation() will be called and it take 5 sec to complete. so my question is
What is the meaning of this line
Task longRunningTask = LongRunningOperation();
what this does int result = await longRunningTask;
The above line could be committed and one line we can construct like
Task<int> longRunningTask = await LongRunningOperation();
or
int result = await longRunningTask;
Please can someone explain to me the above code which is not clear to me.
1) if the longRunningOperation hasn't finished and is still running, MyMethod() will return to its calling method, thus the main thread doesn't get blocked. When the longRunningOperation is done then a thread from the ThreadPool (can be any thread) will return to MyMethod() at its previous state and continue execution (in this case printing the result to the console).
A second case would be that the longRunningOperation has already finished its execution and the result is available. When reaching the await longRunningOperation the compiler knows that it has the result and will keep on executing code on the very same thread. (in this case printing result to console).
point 1 is not at all clear to me like the statement "if the longRunningOperation hasn't finished and is still running, MyMethod() will return to its calling method"
if possible explain the point one in more detail. thanks

I've been taught about it in the following fashion, I found it to be quite a clear and concise explanation:
//this is pseudocode
async Method()
{
code;
code;
await something;
moreCode;
}
When Method is invoked, it executes its contents (code; lines) up to await something;. At that point, something; is fired and the method ends like a return; was there.
something; does what it needs to and then returns.
When something; returns, execution gets back to Method and proceeds from the await onward, executing moreCode;
In a even more schematic fashion, here's what happens:
Method is invoked
code; is executed
something; is executed, flow goes back to the point where Method was invoked
execution goes on with what comes after the Method invocation
when something; returns, flow returns inside Method
moreCode; is executed and Method itself ends (yes, there could be something else await-ing on it too, and so on and so forth)

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.

Behind the scenes C# compiler actually converts your code into a state machine. It generates a lot more code so that behind the scenes every time a await task or async action is completed, it'll continue execution from where it left off. In terms of your question, every time the async action has finished, the async method will be called back on the calling thread when you originally started the call to the async method. Eg it'll execute your code on the thread that you started on. So the async action will be run on a Task thread, then the result will be returned back on the thread you method was originally called on and keep executing.
Await will get the value from the Task or async action and "unbox" it from the task when the execution is returned. In this case it will automatically put it into the int value, so no need to store the Task<int>.
Your code has the problem where it await's on the LongRunningTask() you'd most likely just want to return the long task method without the async, then have your MyMethod perform the await.
int value = await LongWaitingTask()
Async Await and the Generated StateMachine
It's a requirement of async methods that you return a Task or void.
It's possible to change it so when you return back from executing the async task it will execute the remaining code on the thread the async task was performed on using the Task.ConfigureAwait method.

It may be easier to think about it this way:
Whenever you have an await, the compiler splits your method into 2: one part before the await and another part after it.
The second part runs after the first one has finished successfully.
In your code, the first method will look like something roughly equivalent to this:
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
MySynchronousMethod();
longRunningTask.ContinueWith(t => part2(t.Result));
}
void part2(int result)
{
Console.WriteLine(result);
}
Few important notes:
It's obviously much more complex than this since it should support
try-catch and others. Also, it doesn't really use the task
Task is not actually being used directly. It's using the task's GetAwaiter() method and its API, or any other class with this method or extension method.
If there are multiple awaits in a method it's being split multiple times.
If MyMethod is being split, how does someone who awaits MyMethod knows when all parts are done? When your async method returns a Task, the compiler generates a special Task which tracks everything with a state machine.

Related

Can't await task on MainWindow Loaded event [duplicate]

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
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.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

Does calling an async method immediately running its commands

I got this code:
static async Task AsynchronousProcessing()
{
Task<string> t1 = GetInfoAsync("Task 1", 3);
Task<string> t2 = GetInfoAsync("Task 2", 5);
string[] results = await Task.WhenAll(t1, t2);
foreach (string result in results)
{
WriteLine(result);
}
}
static async Task<string> GetInfoAsync(string name, int seconds)
{
await Task.Delay(TimeSpan.FromSeconds(seconds));
return "hi";
}
When reaching the line Task<string> t1 = GetInfoAsync("Task 1", 3);, will it already start asynchronously with the await Task.Delay(TimeSpan.FromSeconds(seconds)); and move on to the rest of the method, or will it return immediatly a task without actually starting it?
And if it won't start when calling the method, will the tasks start only when calling the Task.WhenAll(t1,t2)? Since if it doesn't start right away, I would expect to see GetInfoAsync doing something like return new Task<string>(() => ...);
I recommend reading my async intro.
In summary, all async methods begin executing synchronously. So when AsynchronousProcessing calls GetInfoAsync, then GetInfoAsync begins running, synchronously, just like any other method. An async method can become asynchronous when there is an await. In this case, GetInfoAsync calls Task.Delay (again, synchronously, just like a regular method call), and then passes its Task to await. At this point, await will examine the task; if it is already complete, then it will continue running synchronously; otherwise, it will act asynchronously and return an incomplete task from GetInfoAsync.
The tasks returned from async methods are in progress. I don't usually use the term "running", because they are not actually running code on a CPU and because the task status is not actually Running. This "asynchronous in-progress" state is unfortunately named WaitingForActivation (even though it's not waiting for anything).
Since if it doesn't start right away, I would expect to see GetInfoAsync doing something like return new Task(() => ...);
The async keyword handles the creation of the task. As noted above, the tasks are "hot" or "in progress". This is not the same as "running" or "started", both of which imply tasks that run CPU code. There are two types of tasks: what I call Delegate Tasks and Promise Tasks. The ones returned from async methods are Promise Tasks.
If there aren't any new threads with await, then how will they run in parallel?
They run concurrently (not in parallel, since there is no additional thread blocked on the delay).
However, when the await Task.Delay(..) completes, then there could possibly be another thread used. The await will resume on its captured context and execute the return "hi"; in that context. If the captured context is a thread pool context, then that one line of code will be executed on a thread pool thread. The async state machine translates the return into code that completes the task that was previously returned from that async method.
GetInfoAsync is called and runs synchronously just as usual until it hits the await Task.Delay(TimeSpan.FromSeconds(seconds)) line. It then returns an uncompleted task back to the calling AsynchronousProcessing() method.
So, yes, the task is indeed being started when you call the method, i.e. you don't have to await GetInfoAsync for the Task.Delay method to get called.

When does await examine the awaitable?

Let me quote the code snippet and its relevant explanation from Async and Await article written by Stephen Cleary as follows.
public async Task DoSomethingAsync()
{
// In the Real World, we would actually do something...
// For this example, we're just going to (asynchronously) wait 100ms.
await Task.Delay(100);
}
The beginning of an async method is executed just like any other method. That is, it runs synchronously until it hits an “await” (or throws an exception).
The “await” keyword is where things can get asynchronous. Await is like a unary operator: it takes a single argument, an awaitable (an “awaitable” is an asynchronous operation). Await examines that awaitable to see if it has already completed; if the awaitable has already completed, then the method just continues running (synchronously, just like a regular method).
If “await” sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method.
To accommodate more general case, let me define the code snippet as follows.
public async Task DoSomethingAsync()
{
AAA();
await BBBAsync;
CCC();
}
where BBBAsync is the only "awaitable" operation or method.
For the sake of simplicity, let's assume we execute DoSomethingAsync from within the main app thread. So in my understanding,
AAA() will always be executed synchronously.
BBBAsync() will always be executed asynchronously no matter how DoSomethingAsync() is invoked.
CCC() may be executed either asynchronously or synchronously depending on the result of the await operator determines.
It seems to me, the await operator always find the awaitable has not been completed yet because await always comes before BBBAsync() starts.
Question
When does await examine the awaitable?
It sounds like you think async makes method asynchronous which is not the case. Async only changes how code for the method is generated, but by itself it does not add any asynchronous steps nor run the method on another thread. See many questions like What is the difference between asynchronous programming and multithreading?.
await examines awaitable at the same time irrespective whether it completed yet or not - method like BBBAsync() will eventually return Task that may be either completed or not, but method will return.
Here is an example of task completing synchronously:
async Task BBBAsync() // ignore CS1998 as we don't want `await` inside
{
return;
}
// alternatively the same behavior just returning completed Task
// with FromResult or Task.CompletedTask for 4.6 and later
Task BB2Async()
{
return Task.FromResult(0);
}
You can await such task just fine, but this BBBAsync will complete synchronously and await will pick synchronous branch to continue.
More realistic sample would be returning recently cached value synchronously. This code will generate full state machine for asynchronous execution, but every other call will return synchronously thus making corresponding await to continue synchronously too.
async Task<int> GetValueAsync()
{
if (canReturnCached)
{
canReturnCached = false;
return cachedValue;
}
cachedValue = await SlowRemoteCallForValueAsync();
canReturnCached = true;
return cachedValue;
}

Different Behavior with wait than await [duplicate]

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
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.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

How is async with await different from a synchronous call?

I was reading about asynchronous function calls on Asynchronous Programming with Async and Await.
At the first example, they do this, which I get:
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
string urlContents = await getStringTask;
But then they explain that if there's not any work to be done in the mean time, you can just do it like this:
string urlContents = await client.GetStringAsync();
From what I understand, the await keyword will suspend the code flow until the function returns. So how is this different from the synchronous call below?
string urlContents = client.GetString();
Calling await client.GetStringAsync() yields the execution to the calling method, which means it won't wait for the method to finish executing, and thus won't block the thread. Once it's done executing in the background, the method will continue from where it stopped.
If you just call client.GetString(), the thread's execution won't continue until this method finished executing, which will block the thread and may cause the UI to become unresponsive.
Example:
public void MainFunc()
{
InnerFunc();
Console.WriteLine("InnerFunc finished");
}
public async Task InnerFunc()
{
// This causes InnerFunc to return execution to MainFunc,
// which will display "InnerFunc finished" immediately.
string urlContents = await client.GetStringAsync();
// Do stuff with urlContents
}
public void InnerFunc()
{
// "InnerFunc finished" will only be displayed when InnerFunc returns,
// which may take a while since GetString is a costly call.
string urlContents = client.GetString();
// Do stuff with urlContents
}
From what I understand, the await keyword will suspend the code flow until the function returns
Well, Yes and No.
Yes, because code flow does stop in a sense.
No, because the thread executing this code flow does not block. (The synchronous call client.GetString() will block the thread).
In fact, it will return to its calling method. To understand what it means by return to its calling method, you can read about another C# compiler magic - the yield return statement.
Iterator blocks with yield return will break the method into a state machine - where code after the yield return statement will execute only after MoveNext() is called on the enumerator. (See this and this).
Now, async/await mechanism is also based on similar state machine (however, its much more complicated than the yield return state machine).
To simplify matters, lets consider a simple async method:
public async Task MyMethodAsync()
{
// code block 1 - code before await
// await stateement
var r = await SomeAwaitableMethodAsync();
// code block 2 - code after await
}
When you mark a method with async identifier you tell the compiler to break the method into a state machine and that you are going to await inside this method.
Lets say code is running on a thread Thread1 and your code calls this MyMethodAsync(). Then code block 1 will synchronously run on the same thread.
SomeAwaitableMethodAsync() will also be called synchronously - but lets say that method starts a new asynchronous operation and returns a Task.
This is when await comes into picture. It will return the code flow back to its caller and the thread Thread1 is free to run callers code. What happens then in calling method depends on whether calling method awaits on MyMethodAsync() or does something else - but important thing is Thread1 is not blocked.
Now rest of await's magic - When the Task returned by SomeAwaitableMethodAsync() eventually completes, the code block 2 is Scheduled to run.
async/await is built on the Task parallel library - so, this Scheduling is done over TPL.
Now the thing is that this code block 2 may not be scheduled over the same thread Thread1 unless it had an active SynchronizationContext with thread affinity (like WPF/WinForms UI thread). await is SynchronizationContext aware, so, code block 2 is scheduled over same SynchronizationContext, if any, when the MyMethodAsync() was called. If there was no active SynchronizationContext, then with all possibility, code block 2 will run over some different thread.
Lastly, I will say that since async/await is based on state machine created by compiler, like yield return, it shares some of the shortcomings - for example, you cannot await inside a finally block.
I hope this clears your doubts.

Categories

Resources