Use of await keyword in c# - c#

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

Related

Why waiting an async method that internally awaits a completed task, produces unexpected output? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 days ago.
The community is reviewing whether to reopen this question as of 2 days ago.
Improve this question
I have the following code block:
public class Program
{
public static void Main()
{
Task task = ExampleTaskAsync();
Console.WriteLine("Method invoked");
task.Wait();
Console.WriteLine("main finished");
}
static async Task ExampleTaskAsync()
{
Console.WriteLine("Started await");
await Task.FromResult(189);
Console.WriteLine("During await");
await Task.Delay(867);
Console.WriteLine("completed await");
}
}
When I run this code block, it always produces the following output:
Started await
During await
Method invoked
completed await
main finished
I was expecting the following output:
Started await
Method invoked
During await
completed await
main finished
Could you explain why the "During await" appears before the "Method invoked"?
When you execute Task task = ExampleTaskAsync(); that method starts running synchronously until it hits the first time there is a real Task to wait for. That is why you see "Started await" first.
Next issue is that await Task.FromResult(189); doesn't really wait: FromResult (and Task.CompletedTask) immediately return a completed task so the method doesn't need to wait and continues synchronously. That's why you also see "During await".
Next is a await Task.Delay(867); which immediately returns an imcomplete Task, which does cause the method to return an incomplete task. So you don't yet get to "completed await", but see "Method invoked".
When the delay finishes, the ExampleTaskAsync method continues and prints "completed await". Then the Task belonging to this method is complete and the Wait in the Main is over so you see the final "main finished".
Note that your Main method should also be async (async Task Main()), so you can await task, instead of using Wait() which may cause a deadlock.
When you do this: Task task = ExampleTaskAsync(); You're starting the task .Wait() just waits till its finished, it does not start it (its already started as you can tell).
Just initialize the task variable when you actually want to start the task.
If your are asking why is there a different between
Observed
...
During await
Method invoked
...
Expected
...
Method invoked
During await
...
then the answer is because await Task.FromResult(189); always finishes synchronously.
There is no point to suspend the execution of ExampleTaskAsync and give back the control to the caller.
If you copy-paste the code to sharplab you can see how the execution flow is changing during the application execution.
I also suggest to examine the generated async state machine's code.

Task with/wihout async and await

I have this method :
public static Task TaskMethod ()
{
Task.Delay(30000);
return Task.Run(() => Console.WriteLine("From Task") );
}
If I call it like this:
public static async Task Main()
{
Console.WriteLine("before calling the task");
TaskMethod();
Console.WriteLine("after calling the task");
Console.ReadLine();
}
I have this output:
before calling the task
after calling the task
From Task
But if I call this:
public static async Task Main()
{
Console.WriteLine("before calling the task");
await TaskMethod();
Console.WriteLine("after calling the task");
Console.ReadLine();
}
I have this result:
before calling the task
From Task
after calling the task
Is this behavior normal? Why I'm allowed to await the task without using async?
What I'm missing?
I will try to explain.
Case: You don't await the returning value then it will execute the line and proceed to execute the next.
Console.WriteLine("before calling the task"); // execute 1
TaskMethod(); // execute 2
Console.WriteLine("after calling the task"); // execute 3
The confusing output that you get is because your machine needs less time to execute the 3rd command than it needs to execute the 2nd (creating a task, starting it, printint to console). The 2nd call runs in parallel to the 3rd. This is also due to the fact that the Task.Delay call is not waiting because you don't await it and the same principle applies there as it applies here.
To give you a little examplary proof here is a code that introduces a slight synchronous delay between the 2nd and 3rd call:
public static async Task Main()
{
Console.WriteLine("before calling the task");
TaskMethod();
Thread.Sleep(50);
Console.WriteLine("after calling the task");
//Console.ReadLine();
}
This gives the starting of the 2nd call a little more time to be executed before the 3rd step is performed. And you get the output:
before calling the task
From Task
after calling the task
Now to the fact that the method Main runs actually synchronous on the main thread. This screenshot from LINQPad shows the message that Visual Studio would also display:
It tells you that the main method will block the main thread until it is finished. Because there is no await in it.
Whereas the TaskMethod inside the Main will run asynchronously and in parallel to the next commands which runs on the main thread! Whoever is faster gets to print it's message.
Why the Task.Delay call is useless without await ?=!
The Delay method returns a task which is started, actually quite exactly like your TaskMethod. If you don't await this delay task, it will run in parallel. Thus obliterating the entire effect of a delay. You should actually notice that your console prints all 3 lines at the same time, there is no delay between the second and third line!
Why I'm allowed to await the task without using async?
Because the necessity of async refers always to the method inside which the await call is made and not the method that is awaited! This can be seen in the fact that you cannot simply add an await to the Task.Delay call because the TaskMethod is not declared as async!
(Hopefully) last EDIT:
The await operator needs a Task whose execution it can await, and because your TaskMethod returns a Task the operator can be applied.
You can make nice things with it if you take the returning task. You can then decide when to wait for the end of it's execution!:
public static async Task Main()
{
Console.WriteLine("before calling the task");
Task taskToBeAwaitedMuchLater = TaskMethod();
Console.WriteLine("after calling the task");
await taskToBeAwaitedMuchLater;
Console.WriteLine("after awaiting the result of the task");
//Console.ReadLine();
}
Output:
before calling the task
after calling the task
From Task
after awaiting the result of the task

When will an async await method return from the UI-Thread? At the first await or at the inner await?

I am using async await in WPF on the UI-Thread. I have a question on how async await works in a certain scenario. I will try to explain it on an example.
Background
Let's assume I have the Button A with click event handler ButtonA_Click() and Button B with ButtonB_Click(). The click handlers will check if the RunLoop() method is still running. If it is not running, they start RunLoop().
Question:
Will the event handler return from the UI-Thread when (the outer) await RunLoop() is called?
Or will it return at the (inner) await in RunLoop() because there is synchronous code (_isStopped = false;) it could perform in the beginning of Runloop().
If 1. is true, it could cause a racing condition, or? When both click handlers are called at the same time, they will run right after each other on the UI-Thread. So the second event handler may run before RunLoop() can be executed for the first time. In this case _isStopped would still be false for the 2nd event handler and it would start a RunLoop(), too. Thus 2 RunLoop() would be active. Is that correct?
(PS: I know, that if 1. is the case, I can solve this by putting _isStopped = false into the click handlers, but this question is more about understanding how async await works when the methods are nested this way).
Code
private bool _isStopped = true;
private List<Customer> _customers; // will be filled from somewhere else
public async void ButtonA_Click()
{
// do some stuff synchronously
if (_isStopped)
await RunLoop();
}
public async void ButtonB_Click()
{
// do some stuff synchronously
if (_isStopped)
await RunLoop();
}
private async Task RunLoop()
{
_isStopped = false;
while (_customers.Any())
{
_customers.Remove(...);
await Task.Run(() => ProcessStuff());
}
_isStopped = true;
}
Update after getting the answers:
those links helped me to understand it better
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/control-flow-in-async-programs
Control returns to the calling method when await is given an incomplete Task.
That means that first, await has to be given a Task, which means the method you called has to return before await does anything. And second, the Task has to be incomplete. If await sees a complete Task, execution resumes synchronously.
In your case, lets say ButtonA_Click() runs:
ButtonA_Click() starts running synchronously.
RunLoop() is executed, which starts running synchronously.
Task.Run is executed, which will return an incomplete Task.
The await in RunLoop() sees that incomplete Task and returns its own incomplete Task.
The await in ButtonA_Click() sees that incomplete Task and would normally return a Task, but the method is void, so it returns nothing.
Control is passed to whatever called ButtonA_Click().
Microsoft has some well-written articles on Asynchronous programming with async and await that are worth the read.
It's gonna be the second option. Code in an async method runs synchronously until it encounters an await statement awaiting a non-completed Task.
Note that it might run synchronously all the way if all awaited Tasks are finished before being awaited, or if none of the code actually needs an await statement.

Async method await keyword doesn't suspend to calling method

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.

Async/Await execution steps

Can anyone explain to me why second Working! shows after Done ?
Stating
Doing Work
Working!
Done
Working!
Work completed
Second question why can't I just do like below to get Task result:
Task result = await LongOperation();
And last question is what would be the reason to use Task.Run on behalf with await/async for instance in my code? Where could it be used or is it not good to use it?
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting");
var worker = new Worker();
worker.DoWork();
Console.WriteLine("Done");
Console.ReadKey();
}
}
public class Worker
{
public async void DoWork()
{
Console.WriteLine("Doing work");
await LongOperation();
await LongOperation();
Console.WriteLine("Work completed");
}
private async Task LongOperation()
{
Console.WriteLine("Working!");
await Task.Delay(200);
}
}
This is because you have declared DoWork() asynchronous with a return type of void. This makes it a "fire and forget" method that is running asynchronously. If you have DoWork() return a Task instead of void, you can await it, and that would ensure your "Done" message would occur after DoWork() has completed execution.
Additionally, await unwraps the task result, so you cannot await it and get the value at the same time. If you wish to use the Task result directly, do not await it.
There is no specific area in the code you specified where you should be using Task.Run().
Working shows after Done! because in your static void Main you aren't waiting for worker.DoWork(); to complete, so the program executes the next line. You should change DoWork method like this:
public async Task DoWork()
{
//
}
And change the call to it like this:
worker.DoWork().GetAwaiter().GetResult();
You can't because using await your LongOperation will not return a Task. For example if you had a signature like this, when you use await you unwrap the result:
public Task<int> GiveANumberAsync()
{
return Task.FromResult(12);
}
int result = await GiveANumberAsync();
For this question I think I can't explain better than Stephen in this answer, where he says:
Use Task.Run to call CPU-bound methods.
There reason "Done!" appears sooner than you expect is because you do not have await in front of worker.DoWork(); (and DoWork needs to return a Task to be able to use await). So what happens is DoWork() returns immediately with execution deferred to another thread, and immediately goes to next line which is the console write "done".
Regarding Task result = await LongOperation();, await takes in as parameter awaitable object (i.e. Task), examines its .Result property on your behalf, extracts the result and returns it. So you either drop await to get the task instance, or you put await to wait for task completion and extracting the actual return value of the call.
There are a few reasons to use Task.Run or through task factory, one example being passing lambda function for execution (possibly with closure). I would refer to MSDN library on TPL for detailed dive.
Taking your questions one by one:
In Main, you do not await DoWork. This means that it is invoked, and then execution of the code in the Main continues, without waiting for DoWork to finish. As such, "Done" is printed to the console right away before the second "Working".
This isn't what the await keyword does. From the documentation:
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work. [...]
The task to which the await operator is applied typically is the return value from a call to a method that implements the Task-Based Asynchronous Pattern. Examples include values of type Task or Task<TResult>.
Effectively, in order to await a method, it must have return type Task<T>, where T is the actual type of what you return in your code. Your method LongOperation doesn't actually return anything in this example.
Task.Run is used to run any method or block of code as a Task. It can be fired and forgotten (Task.Run([something];), or awaited like any other task (await Task.Run([something]);. See the documentation for it here, though I'm not sure it will be much help. User Stephen Cleary explained it well in this answer, along with some other pertinent information.

Categories