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

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.

Related

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

Is a method always async if it has the key word "async" and "await"? [duplicate]

I've been trying to understand async/await and Task in C# but have been failing spectacularly despite watching youtube videos, reading documentation and following a pluralsight course.
I was hoping someone might be able to help answer these slightly abstract questions to help my brain out.
1.Why do they say that async/await enables an 'asynchonrous' method when the async keyword on it's own does nothing and the await keyword adds a suspension point? Isn't adding a suspension point forcing the method to act synchronously, i.e. finish the task marked by the await before moving on.
2.Apparently you are not supposed to use async void except for event handlers, so how do you call an async method normally? It seems that in order to call an async method by using the await keyword, the method/class that is calling it itself needs to be marked as async. All the examples I've seen have 'initiated' an async void method with an event handler. How would you 'escape' this wrapping of async/await to run the method?
3.
public async Task SaveScreenshot(string filename, IWebDriver driver)
{
var screenshot = driver.TakeScreenshot();
await Task.Run(() =>
{
Thread.Sleep(2000);
screenshot.SaveAsFile(filename, ScreenshotImageFormat.Bmp);
Console.WriteLine("Screenshot saved");
});
Console.WriteLine("End of method");
}
Relating back to 1. this looks like a synchronous method. Execution pauses when it gets to Task.Run, therefore Console.WriteLine("End of method"); will not be executed until the task is finished. Maybe the whole method itself will be executed asynchronously at the point it is triggered in the code? But relating back to 2, you need to call this with an await otherwise you get the message 'Because this call is not awaited..' therefore adding an await will cause that execution point to be synchronous and so on and so.
Any help understanding this would be much appreciated.
Isn't adding a suspension point forcing the method to act synchronously, i.e. finish the task marked by the await before moving on.
No, the word you're thinking of is "sequential", not "synchronous". await results in asynchronous sequential code. "Sequential" meaning "one at a time"; "synchronous" meaning "blocking until completed".
how do you call an async method normally?
Using await.
How would you 'escape' this wrapping of async/await to run the method?
Ideally, you don't. You go async all the way. Modern frameworks (including ASP.NET MVC, Azure Functions / WebJobs, NUnit / xUnit / MSTest, etc) all allow you to have entry points that return Task. Less-modern frameworks (including WinForms, WPF, Xamarin Forms, ASP.NET WebForms, etc) all allow async void entry points.
So, ideally you do not call asynchronous code from synchronous code. This makes sense if you think about what asynchronous code is: the entire point of it is to not block the calling thread, so if you block the calling thread on asynchronous code, then you lose all the benefits of asynchronous code in the first place.
That said, there are rare situations where you do need to treat the code synchronously. E.g., if you are in the middle of a transition to async, or if you are constrained by a library/framework that is forcing your code to be synchronous and won't work with async void. In that case, you can employ one of the hacks in my article on brownfield async.
Your understanding is pretty good :). The main point you seem to be missing is that "asynchronous" methods in .NET mean methods that can stop execution without blocking the calling thread.
As you pointed out in (1), the async keyword basically enables the use of await and requires the return type to be void or Task/Task<T>. await just instructs the current method to suspend execution until the task is complete.
What you are missing here is that it suspends just the current method. It does not block the thread the method was executing on. This is important in cases like the UI thread of a WPF application. Suspend method execution and everything keeps running, block the thread and the application stops responding.
You usually want your async calls to go all the way to the top (like an event handler), this allows the most flexibility and prevents deadlock situations. However; you can wait for a Task returning method to complete with Wait:
someAsyncMethod.Wait()
Or get the return value:
var result = someAsyncMethod.Result;
Note that both of these are synchronous and block the calling thread. Doing this can cause deadlock if the async task is waiting for some other work on the calling thread to complete.
The above should answer your question in (3); the method itself appears to execute synchronously (this is the magic of await/async) but the task doesn't block the calling thread.
It is asynchronous because you don't have to wait the method to return. In your code, you may call the async method and save the task in a variable. Continue doing something else. Later, when the method result is needed, you await the response (task).
// Synchronous method.
static void Main(string[] args)
{
// Call async methods, but don't await them until needed.
Task<string> task1 = DoAsync();
Task<string> task2 = DoAsync();
Task<string> task3 = DoAsync();
// Do other stuff.
// Now, it is time to await the async methods to finish.
Task.WaitAll(task1, task2, task3);
// Do something with the results.
Console.WriteLine(task1.Result);
Console.ReadKey();
}
private static async Task<string> DoAsync()
{
Console.WriteLine("Started");
await Task.Delay(3000);
Console.WriteLine("Finished");
return "Success";
}
// Output:
// Started
// Started
// Started
// Finished
// Finished
// Finished
// Success

Use of await keyword in 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

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.

Task.Run how it works [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I guess it's simple but I have some misunderstanding in the work of tasks
When I call the code below it's works well, I get a result in about 1 sec.
return Task.Run(() => SendRequest<IADsystem[]>(path)).Result;
But this one never returns a result:
Task<IADsystem[]> task = SendRequest<IADsystem[]>(path);
task.Wait(); //also tried without wait
return task.Result;
I thought maybe the task didn't start and I need to call Start(), but when I made it I got "Start may not be called on a promise-style task" exception.
SendRequest method:
private async Task<T> SendRequest<T>(string requestUri) where T : class
{
var authHandler = new HttpClientHandler();
authHandler.Credentials = CredentialCache.DefaultNetworkCredentials;
using(var client = new HttpClient(authHandler))
{
client.BaseAddress = apiServerURI;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(jsonAcceptType);
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
else
return null;
}
}
Please, explain how it works
Consider the Wait() approach first:
Task<IADsystem[]> task = SendRequest<IADsystem[]>(path);
task.Wait(); //also tried without wait
return task.Result;
This code is using the sync-over-async antipattern. This can cause a deadlock, as I describe in detail on my blog. The core problem is that your code is blocking on asynchronous code. This works in some scenarios, but in this case you're seeing the common deadlock.
In summary, this is due to await capturing the current context (usually a SynchronizationContext), and using that to resume its async method. Thus, if you call this code from a UI thread (or ASP.NET request context), then the awaits inside SendRequest will attempt to resume on that context, but the context is blocked by the Wait/Result, resulting in deadlock.
Note that the problem is due to synchronously calling an asynchronous method; the ideal solution is to go "async all the way", as I describe in my async best practices article.
Back to the actual question:
Task.Run how it works
When I call the code below it's works well
return Task.Run(() => SendRequest<IADsystem[]>(path)).Result;
Sort of. It "works" in the sense that it does not deadlock. However, it's not ideal because it blocks a thread pool thread for the duration of the request. A better solution would be to use async all the way.
But leaving that aside for the moment, the reason why it works is because it "steps outside" the calling context. Task.Run executes the SendRequest on a thread pool thread (one without a UI or ASP.NET request context), and as such the awaits in SendRequest resume on thread pool threads. This is why your calling thread can block on it without deadlocking.
But it still shouldn't block on the task; it should await it instead.
async/await methods must be async/await all the way through. If you are using Windows Forms, then whatever event handler contains the code that calls SendRequest must be marked as async. Every method between the UI event handler and your SendRequest must also be marked async, and they must be awaited. You should then
var result = await SendRequest<IADsystem[]>(path);
like Fabio suggests.
Here is some more information about async/await.
I started learning about async here in this page so I assume it is good starting point. I urge you to look at execution context Async - Starting Point
Coming to why you have a dead lock, I will try to explain. When you called task.Wait(), you are basically telling your current thread to wait for the result to continue. So right now your current thread, or your Execution Context is waiting for the result to continue. Let us continue. When you called task.Wait(), you entered private async Task<T> SendRequest<T>(string requestUri)... method and the moment you reached return await response.Content.ReadAsAsync<T>(); you passed your current execution context, which is waiting the result from SendRequest<T>. Right now, you are in a dead lock. Why? Your UI thread is waiting an answer from SendRequest<T> and in order for SendRequest<T> to finish (or return), it needs to access to UI thread but you can not access the UI thread because it is waiting for SendRequest<T> to finish but for SendRequest<T> to finish it needs to access to UI thread....

Categories