I have following line of code, to understand async-await and suspension till awaited task complete.
public async Task<string> WaitAsynchronouslyAsync()
{
var results = await WaitAsync();
Console.WriteLine($#"I am not waiting");
return results;
}
public async Task<string> WaitAsync()
{
await Task.Delay(10000).ConfigureAwait(false);
return "Async programming suspension point demo.";
}
The await operator suspends execution until the work of the WaitAsync() (Delay 10 seconds) method is complete.
In the meantime, I was expecting that Console.WriteLine($#"I am not waiting"); should write text to output window until awaited task completes, as control is returned to the caller of WaitAsync(). When the task finishes execution, the await expression evaluates string ("Async programming suspension point demo.").
Am I confused here with suspension pointer vs debug pointer?
The await operator suspends execution until the work of the WaitAsync() method is complete.
Correct.
I was expecting that Console.WriteLine($#"I am not waiting"); should write text to output window until awaited task completes, as control is returned to the caller of WaitAsync().
Why? You just said the await operator suspends execution until the work is complete. The work will not be complete for another ten seconds; the work is to wait for ten seconds. The work of WaitAsync is not complete until it executes the return, and that is in the future.
The right thing to do here is for WaitAsynchronouslyAsync to allow its caller an opportunity to run in this scenario.
You have correctly stated the meaning of await, but you seem to not be fully internalizing the consequences. An await checks its operand to see if the task is complete. If it is, then the result of the task is fetched and the method continues. If it is not, then the remainder of the method is signed up as the continuation of that task, and control is yielded so that more work can be done elsewhere. In the future, when the task completes, the remainder of the method is scheduled to execute.
await means "wait until this finishes executing asynchronously" your function will not continue until the supplied Task finishes executing.
If you instead said the following it wouldn't wait:
var results = WaitAsync();
Console.WriteLine($#"I am not waiting");
return await results;
Or even more succinctly, remove the async from the signature and then you can just return results;.
The sequence of operations will go something like this:
You call WaitAsynchronouslyAsync
WaitAsynchronouslyAsync calls WaitAsync
WaitAsync calls Task.Delay(10000).ConfigureAwait(false), which produces a Task.
WaitAsync returns a new Task to its caller, WaitAsynchronouslyAsync, which will be completed later
WaitAsynchronouslyAsync awaits the task from WaitAsync, and then returns to it's caller, providing a Task representing when it will be finished.
Other stuff happens further up the call stack.
Task.Delay finishes, so the continuation of WaitAsync fires, picking up where it left off.
WaitAsync returns the string, completing the Task.
WaitAsynchronouslyAsync can now continue, since the Task returned from WaitAsync has finished. It will go on to print out text to the console.
WaitAsynchronouslyAsync finishes it's task, letting anyone who has anything set up to run when it's finished to be able to run.
Related
I have issues understanding a detail about async programming in C#.
Lets say I have a common async method, that has a few await statements in it. Lets say I have another method, which is not async, but calls the first method.
public void DoSomething(){
DoSomethingAsync()
...
}
public async Task DoSomethingAsync(){
...
await ...
...
}
I know i could just use Wait() or some other synchronization technique, but i dont just want to throw stuff at problems without knowing what happens.
Will DoSomething continue execution before DoSomethingAsync is completed? I know that this would happen if DoSomething were to be declared async, but it isn't.
Or to be more general: Can synchronous methods continue their execution before an asynchronous sub-call has completed?
TL;DR It continues
Can synchronous methods continue their execution before an
asynchronous sub-call has completed?
Of course it can, if a synchronous method has to wait an asynchronous method to finish, what's the purpose of going asynchronous? (It can wait as well, depending on what you want to achieve)
async/await pattern in your code will create a state machine that can be recovered later. By the time your code hits await, the task you await on will be pushed to the task scheduler and might be executed in some threadpool thread. The async method returns and let the synchronous method continue.
When the task is finished, the state machine recovers the context, and everything in DoSomethingAsync after await continues. On which thread it would run? This depends on if you set ConfigureAwait and the threading model of your program. For example, for a WPF application, by default, it comes back to the main thread, and that's why wait + await can lead to deadlocks.
What happens is:
DoSomething calls DoSomethingAsync.
Then a synchronous! order starts until the first "await" is reached.
With this await, the DoSomethingAsync returns a Task object the has status "not finished yet". But as you do not assign this return value and also do nothing else special your DoSomething continues.
In the absence of the await operator this method will behave as if this call is not awaited, execution of the current method continues before the call is completed
The compiler will warn you:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs4014?f1url=%3FappId%3Droslyn%26k%3Dk(CS4014)
Can synchronous methods continue their execution before an asynchronous sub-call has completed?
As others have noted, the answer to this is "yes".
All asynchronous methods begin executing synchronously. They return a task that represents the completion of that asynchronous method. The task is completed when the asynchronous method is completed. If the asynchronous method returns a result, then the task is completed with a result value. If the asynchronous method throws an exception, then the task is completed with an exception (i.e., faulted).
However, this also means that there is are some problems with the code you've posted. Specifically, it's doing a kind of "fire and forget", and that's dangerous.
This code is just ignoring the task returned from DoSomethingAsync:
public void DoSomethingElse(){
DoSomethingAsync()
...
}
So that means it's saying "start doing something" and it's also saying "I don't care if or when that 'something' completes, and I don't care if it throws an exception". There are a couple problems with this: 1) since your app doesn't know when "something" completes, it can't know when it's safe to shut down, and 2) your app won't be notified if "something" fails.
In the vast, vast majority of scenarios, that means the app has bugs. "Fire and forget" is only appropriate when doing an operation where it doesn't actually matter if the operation fails or isn't even completed. There are very few operations where this is the case.
This is why - as a general rule - tasks should eventually be awaited. If you want to start an operation and then do other things and then await that operation to complete, that's not uncommon:
public async Task DoSomethingElseAsync() {
var task = DoSomethingAsync();
... // other synchronous/asynchronous work.
await task; // asynchronously wait for DoSomethingAsync to complete,
// and propagate any exceptions.
}
I have a doubt. I have read that await keyword is used when we want to wait for a particular function to finish the operation.
public async void Work()
{
await SlowTask();
Console.WriteLine("Execution completed");
}
Now as per the definition, when Work() method is called, it will wait for SlowTask() method to complete its execution before printing "Execution completed". But I have a doubt that even if the await and async keyword are not used then also Work() method is going to wait for SlowTask() method to complete its execution before printing "Execution completed" because it will be executed line by line.
But I have a doubt that even if the await and async keyword are not used then also Work() method is going to wait for SlowTask() method to complete its execution before printing "Execution completed" because it will be executed line by line.
If you don't use await, it will wait for the SlowTask method to return - but it won't wait for it to complete. This is one of the trickiest aspects of understanding async/await: an async method returns as soon as it needs to await something that hasn't finished, but then it continues when that has completed.
So suppose SlowTask is:
async Task SlowTask()
{
Console.WriteLine("A");
await Task.Delay(5000);
Console.WriteLine("B");
await Task.Delay(5000);
Console.WriteLine("C");
}
This method will print A as soon as it's called, but will return when it hits the first await, because the delay won't have been completed. If you don't await SlowTask in your calling code, you'll then see "Execution completed" even though SlowTask hasn't really completed.
After the first delay has completed, SlowTask will resume, and B will be printed. It will return again (to whatever scheduled the continuation) due to the second delay, then continue and print C before completing. If you've actually awaited the task returned by SlowTask that's when you'll see "Execution completed" printed - which is probably what you want.
One thing that always helped see the difference when I first came to learn about was this scenario.
Public async Task StartTaskAsync()
{
Console.WriteLine("First Step");
Task awaitableTask = OtherMethodAsync();
Console.Writeline("Second step");
await awaitableTask;
Console.Writeline("4th Step");
}
Public async Task OtherMethodAsync()
{
await Task.Delay(2000);
Console.WriteLine("Step 3");
}
If you run this it will print out the steps in order. Because the await in the OtherMethodAsyncAsync passes control back to the calling method until whatever it is await has finished.
In the calling method StartTaskAsync it doesn't await immediately so it can continue to run some code until it waits on the task returned by the OtherMethodAsyncAsync.
If you were to make this synchronous. Ie remove all the asyncs and awaits and just return void rather than task. You would see that step 3 prints before Step 2
I am new in async programming and my question might look silly. Can anybody, please, explain how async calls work in the following pseudo code example?
public async Task MyMethod()
{
while(true)
{
await Method1();
//do something in MyMethod
await Task.Delay(10000);
}
}
private async Task Method1()
{
//do something in Method1 before await
await Method2();
//do something in Method1 after await
}
private async Task Method2()
{
//do something in Method2 before await
await LongRunMethod();
}
In my understanding, the program works like this
MyMethod() calls Method1() in infinite loop
Method1() runs "do something in Method1 before await"
Method1() starts Method2() and returns control to MyMethod()
MyMethod() starts 10000 ms delay and returns control to its caller
Method2() completes "do something in Method2 before await", starts LongRunMethod() and returns control to MyMethod1()
Method1() completes "do something in Method1 after await". What method does get control after that?
LongRunMethod() finishes its work
Method2() finishes its work. Does it return control to Method1()?
After 10000ms, everything repeats from step 1.
My questions are
Is the above steps sequence correct?
What methods do get control after Method1() and Method2() finish their work in steps 6 and 8?
What is going to happen if LongRunMethod() runs longer than 10000ms?
Thank you
Is the above steps sequence correct?
No.
The correct sequence is
MyMethod calls Method1.
Method1 does the code before the call to Method2.
Method1 calls Method2.
Method2 does the code before the call to LongRunMethod.
Method2 calls LongRunMethod.
LongRunMethod returns a task to Method2.
Method2 interrogates the task to see if it is complete. Let's suppose it is not.
Method2 signs up "do no additional work, and then mark method2's task as complete" as the continuation of the task just returned, and returns its task to Method1.
Method1 interrogates the task just returned from method2. Let's suppose it's not complete. It assigns the work that happens after the await as the continuation of method1's task, and returns that task to its caller.
MyMethod interrogates the task just returned from Method1. Let's suppose it's not complete. It signs up the remainder of that work to the continuation of its task, and returns that task to its caller.
That caller, whatever it is, does whatever work it does.
At some point in the future, LongRunMethod's task completes asynchronously and requests that its continuation be resumed in the appropriate context.
Eventually that context gets to run code, and it runs the continuation of the LongRunMethod task, which is, recall, to do no work and then mark the Method2 task as complete.
It does so. Method2's task is now complete, so it requests its continuation to run on the appropriate context.
Eventually that runs. Recall that Method2 task's continuation is to run the remainder of Method1. It does so, and then marks Method1's task as complete. That requests that Method1's task run its continuation.
Eventually that continuation runs. Its continuation is to call Task.Delay.
Task.Delay returns a task. MyMethod interrogates the task. It's not complete. So it signs up "go back to the top of the loop" as the continuation of that task. It then returns.
Whatever code triggered the continuation of LongRunMethod's task keeps doing work. At some point ten seconds in the future the delay task completes and requests that its continuation executes.
Eventually the continuation executes on the appropriate context. The continuation is "go back to the top of the loop", and the whole thing starts over.
Note that the task returned by MyMethod never completes normally; if any of those tasks throw exceptions then it completes exceptionally. For simplicity I've ignored the checks for exceptional continuation in your example, since there is no exception handling.
What methods do get control after Method1() and Method2() finish their work?
The remainder of Method1 eventually gets control after the task returned by Method2 is completed. MyMethod eventually gets control after the task returned by Method1 is completed. The exact details of when the continuations are scheduled depends on the context in which the code is running; if they're on the UI thread of a form, that's very different than if they're in worker threads on a web server.
What is going to happen if LongRunMethod() runs longer than 10000ms?
I think you mean what happens if the task returned by LongRunMethod does not complete for more than ten seconds. Nothing particularly interesting happens then. The delay is not started until after LongRunMethod's task is done. You awaited that task.
I think you fundamentally do not understand what "await" means. You seem to think that "await" means "start up this code asynchronously", but that is not at all what it means. The code is already asynchronous by assumption. Await manages asynchrony; it does not create it.
Rather, await is an operator on tasks, and it means if this task is complete then keep going; if this task is not complete then sign up the remainder of this method as the continuation of that task and try to find some other work to do on this thread by returning to your caller.
No code that is after an await executes before the awaited task is completed; await means asynchronously wait for the completion of the task. It does NOT mean "start this code asynchronously". Await is for declaring what points in an asynchronous workflow must wait for a task to finish before the workflow can continue. That's why it has "wait" in the name.
As far as I know the async await keywords work this way: when an await keyword is encountered by the compiler, it suspends the execution of the async function to the caller (in this case the dispatcher), waits for the awaitable function to complete in the background and then then returns back to the function. Am I right?
here is what I am doing:
async private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var p = await query("select* from notes", con);
}
and here is the function being called
async Task<List<notes>> query(string sqlstring, SQLiteConnection con)
{
var p = con.Query<notes>(sqlstring);
Thread.Sleep(5000);
MessageBox.Show(p[0].Data);
return p;
}
This blocks the UI thread. why is this happening shouldn't the control be transferred back to the dispatcher when it encounters the await keyword? If so why does the UI get stuck?
Your understanding of await is mostly correct, it's just incomplete. await doesn't suspend execution of the current method immediately. First, the value to be awaited needs to be resolved to a value. Typically you'll have some sort of method that creates a Task. That task will be created synchronously, and then after creating that task, execution of the current method will end, and a continuation will be applied to that task that executes the remainder of the method.
For an async method everything before the first await will be performed synchronously by the caller. It is when the first await (or the end of the method, or an exception that isn't caught by the method) that causes the method to return an actual Task.
Your query method should be able to create the Task that represents the completion of the operation very quickly and then return, so that the caller can await that Task. But it doesn't, it spends over 5 seconds creating the task that represents when it will finish, and when it ends up giving that task to its caller that Task has already finished.
This means that Button_Tap can't yield to its caller (which is the UI's message loop) until after query has finished its 5 seconds of task creation.
All of this means that for Button_Tap to be asynchronous query needs to be asynchronous, and not asynchronous in that it uses the async keyword, but asynchronous in the sense that the method returns almost immediately when called, and that it performs its work after yielding control back to the caller.
As to how to make the method asynchronous, that'll depend. For IO, such as querying a database, what you really want is to have the query provider itself provide inherently asynchronous support. You want to have a query method that returns a Task that you can await, rather than synchronously returning its results. If you have no other choice, then as a last resort you can use Task.Run to perform the query in a non-UI thread and then await that.
As for the Thread.Sleep, that is also synchronously blocking the thread. You need to asynchronously do something after a set period of time instead (if you really do need the delay). You can use Task.Delay for that.
async Task<List<notes>> query(string sqlstring, SQLiteConnection con)
{
var p = await con.QueryAsync<notes>(sqlstring);
//Or, if there is no asynchronous query method
//var p = await Task.Run(() => con.Query<notes>(sqlstring));
await Task.Delay(5000);
MessageBox.Show(p[0].Data);
return p;
}
On a side note, you really shouldn't be trying to re-use your database connections like this. They aren't designed to be used concurrently, for starters. Really they're inherently designed to perform just a single operation. You should be creating your connection right when you need it, and cleaning it up as soon as that one operation has been performed.
After playing with .NET 4.5 async\await framework I have a question.
Let's look at this program (the msdn example):
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
The program will run in this order:
new HttpClient.
GetStringAsync invoke synchronously.
In some point, GetStringAsync calls await and the control return to AccessTheWebAsync.
DoIndependentWork invoked.
The program waits the string to be returned (blocks if the operation didn't complete).
return the length of the urlContent.
One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).
In oreder to run the method asynchronously, we need to use Task.Run or Task.Factory.StartNew explicitly.
But the real question is, if we have independent work, why not do it right away rather then waiting the await to be called from GetStringAsync? (In other words, why async methods doesn't run asynchronously by definition?)
EDIT:
I'll rephrase the second and third operations:
(2) GetStringAsync start synchronously.
(3) In some point, GetStringAsync calls await and the thread forks, the control return to AccessTheWebAsync.
One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).
That is incorrect. GetStringAsync returns a Task<string>. It will return immediately, which means DoIndependentWork will (potentially) run before the download has completed. The await operator will asynchronously wait until the Task<T> returned by GetStringAsync is done.
But the real question is, if we have independent work, why not do it right away rather then waiting the await to be called from GetStringAsync? (In other words, why async methods doesn't run asynchronously by definition?)
The actual "work" of the asynchronous methods is running after the method has returned. The Task that's returned will (normally) be in a state that's not completed, which means the method is still running asynchronously. You can check Task.IsCompleted to verify.
Try this:
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
Debug.WriteLine("Completed? {0}", getStringTask.IsCompleted); // Will likely print false
DoIndependentWork();
string urlContents = await getStringTask;
Debug.WriteLine("Completed now? {0}", getStringTask.IsCompleted); // Will always print true
Each async method is split into segments on each await. Each segment will become a state on a compiler generated state machine.
Each await instruction works on an awaitable for which a Task is the most common case.
Each state/segment will be executed synchronously until the where the received awaitable is checked if it is already completed.
If the awaitable is completed, it execution will continue on the next state.
If the awaitable is not completed and there isn't a current SynchronizationContext, the execution will be blocked until the the awaitable is completed at which time the execution of the next state will be started.
If a current SynchronizationContext exists, the execution will return to the caller and when the awaitable is completed the continuation to the next state will be posted to the captured SynchronizationContext.
The program waits the string to be returned (blocks if the operation
didn't complete).
await doesn't block on await getStringTask. It will save the internal state of the AccessTheWebAsync method (local variables and where the execution point is) in a compiler-generated state machine object and will return to the outer method which called AccessTheWebAsync. The state will be restored and the execution will be resumed later asynchronously when getStringTask task has become completed, via a compiler-generated continuation callback. If you're familiar with C# iterators and yield keyword, the await state machine control flow is very similar to it, albeit iterators are executed synchronously.
How exactly the execution will be resumed after await depends on the synchronization context of the thread initiating the await. If it's a UI thread pumping Windows messages, the continuation callback will likely be called on the next iteration of the thread's message loop (typically inside Application.Run). If it's a non-UI thread (e.g., a console application), the continuation may happen on a different thread at all. So, while the control flow of your method remains logically linear, technically it is not (as it would have been if you just did getStringTask.Wait() instead of await getStringTask).
The program waits the string to be returned (blocks if the operation didn't complete).
No, it doesn't. await waits, but it doesn't block any threads. That's the whole point.
One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).
That's wrong. Most of the method does run asynchronously. It most likely also has a small synchronous part at the start, but that should be negligible.
In oreder to run the method asynchronously, we need to use Task.Run or Task.Factory.StartNew explicitly.
No, the method already does run asynchronously. If you want to run the small synchronous part on another thread, then you can use Task.Run(), but that almost never makes any sense. Also, don't use StartNew() for this, it doesn't work well with async methods.
In other words, why async methods doesn't run asynchronously by definition?
A significant point about await is that it resumes on the same context where it left.
This can be very useful in GUI applications, where you often want to modify the UI, then execute the async operation and then modify the UI again. If async automatically meant that the whole method executes on a ThreadPool thread, then that wouldn't be possible.
Also, doing it this way is more efficient, because you don't have to switch to another thread for something that takes very little time.