Await doesn't block calling thread [duplicate] - c#

This question already has answers here:
How and when to use ‘async’ and ‘await’
(25 answers)
How do yield and await implement flow of control in .NET?
(5 answers)
Brief explanation of Async/Await in .Net 4.5
(3 answers)
Closed 2 years ago.
I never had a good chance to go deep into async/await , so I have just a gist of what it does.
So I tried it in WinForms app like this:
private async void button2_Click(object sender, EventArgs e)
{
// In below line I understand the Task is created and scheduled to execute, which in this
// simple case means, that it executes right away asynchronously.
var task = Task.Factory.StartNew(() =>
{
Task.Delay(5000).Wait();
return 12;
});
// Here we wait for the task to finish, so we don't see MessageBox yet.
var res = await task;
MessageBox.Show("Result is :" + res);
}
My question is, since we are waiting on await I expected to block UI thread, since we can go any further in that thread (to the line with MessageBox). So UI thread actually stops on method with event hadnler.
But, to my surprise, windows is responsive and everything works very well, but I didn't expect that. Can anybody explain me what is going on?
After reading this post, I still have a doubt, if await is asynchronous and doesn't block UI thread in my example, why the thread doesn't proceed to next line with MessageBox? How the UI thread proceeds then?
Is good idea that code after await is just another Task, like in ContinueWith? But it comes back to UI context?

Async methods are a lot like generator methods. The compiler will split up your code at each await operator. A block of code is inserted to check if the task is already complete, in which case the method immediately continues. Or if the task is not complete, a callback is registered to continue execution later, and your method returns.
Returning early is the whole point of an async method.

Related

Multiple Task.Run vs no await for async method? [duplicate]

This question already has answers here:
When should you use Task.Run() rather than await?
(2 answers)
is using an an `async` lambda with `Task.Run()` redundant?
(3 answers)
What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?
(2 answers)
Closed 3 years ago.
I have some IO-Bound jobs(periodically write some data to file) codes as follows:
public async Task SaveToFile1(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile2(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile3(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
The caller is the main method.
The tasks worked fine and produced the correct result when I run them with 2 ways as follows:
void main ()
{
// other codes
// way 1:
SaveToFile1(1000);
SaveToFile2(1000);
SaveToFile3(1000);
// other codes will not let the app exit
}
void main ()
{
// other codes
// way 2:
Task.Run(async() => await SaveToFile1(1000));
Task.Run(async() => await SaveToFile2(1000));
Task.Run(async() => await SaveToFile3(1000));
// other codes will not let the app exit
}
Which is the right way or another way is the best choice for my situation?
Thanks for your answers!
Edit:
In way 1, when await Task.Delay 'complete', a new thread-pool thread may be captured to execute the loop's next step, ..., loop will always running in other thread at the await hit.
In way 2, may be a new thread-pool thread will be used when Task.Run execute immediately, loop will always running in other thread at the begin.
The result are the same, where is the diffrence?
So my question is not about Task.Run vs async-await!
Asynchronous code allows the current thread to be freed to do other work while waiting for a response from something else. But all the code before the first await will be done on the same thread you call it from. If that code is significantly CPU-heavy, it could be noticeable.
If you don't use Task.Run, the method will be run on the same thread up until the first asynchronous I/O request, when it will return a Task and your next method will be called.
Task.Run will execute the code on a different thread. This is good if it does do some CPU-heavy work and you don't want that done on the current thread (like in a desktop app where you don't want it done on the UI thread). But there is a small cost to starting up a new thread too.
Whether using Task.Run will make any noticeable difference depends on the type of app you're writing and what your methods do.
It's fine if you don't await them immediately, but if you don't ever await them, then you will never know when they finished, if they finished successfully, or threw and exception. This is called "fire and forget". Do that only if you don't care if they succeed.
Instead, you can wait at the end to make sure they completed successfully. For example:
void main ()
{
// other codes
var taskList = new List<Task>();
taskList.Add(SaveToFile1(1000));
taskList.Add(SaveToFile2(1000));
taskList.Add(SaveToFile3(1000));
// other codes will not let the app exit
// wait till everything finishes before exiting
await Task.WhenAll(taskList);
}

UI Received task got cancelled [duplicate]

This question already has answers here:
'await' works, but calling task.Result hangs/deadlocks
(6 answers)
Closed 3 years ago.
In my application, I am trying to update the user profile which calls the Rest API. API has one sync method UpdateProfile where execution getting stuck.
this line of code is ending the execution
command.UserProfile.LookupItems = GetLookupItemsByUserId(existingUser.Id).Result;
When i changed this line of code to
command.UserProfile.LookupItems = Task.Run(async () => await GetLookupItemsByUserId(existingUser.Id)).Result;
It started working without any issue.Can anybody explain to me what is going on behind the scene?
The first version is blocking the current thread, when the task complete the blocked thread cannot catch it.
YourType Signature() {
var neverUsedValue = task.Result;
}
The second one is yielding the current "thread" until the task is returned.
YourType Signature() {
var value = Task.Run(await => async MethodThatWillComplete()).Result
}
What you should do is propagate the async to the method:
async Task<YourType> SignatureAsync() {
command.UserProfile.LookupItems = await GetLookupItemsByUserId(existingUser.Id);
}
In this way you will avoid handling the AggregateException.
There is very well written article on this here:Don't block async
In a few words, blocking on async code is bad because it may be blocking the thread which is supposed to run the async code and thus generete a deadlock.

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....

Async/Await VS Task.Run : When to use ? How to use?

Okay I hope I got the basics of async/await but still some questions a re lingering in my head.
But now it is the problem I am talking about . Suppose in this simple example
static void Main(string[] args)
{
Method();
Console.WriteLine("Main Thread");
Console.ReadLine();
}
public async static void Method()
{
await Task.Run(new Action(LongTask));
Console.WriteLine("New Thread");
}
public static void LongTask()
{
Thread.Sleep(8000);
Console.WriteLine("Long Task");
}
The main thread still continues and prints Main Thread after calling Method() and encountering an await for 8 seconds .
So accordingly the Method() returns to the caller i.e. to the main function here once it encounters await , saves the synch context and keeps on executing from there .
It prints Main Thread first .
Then after 8 seconds complete , Long Task and then New Thread get printed.
This part I got . My question is in my application :
public IList<createcaseoutput> createCase(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)
{
.............
SQL.CaseSQL.getCreateCaseParameters(CreateCaseInput, out strSPQuery, out listParam);
var AcctLst = rep.ExecuteStoredProcedure<createcaseoutput>(strSPQuery, listParam).ToList();
if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
{
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
}
console.writeline("Async called");
return AcctLst;
}
public async Task<ilist<savecasesearchoutput>> saveCaseSearch(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
..........................
SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);
var AcctLst = await rep.ExecuteStoredProcedureAsync<entities.case.savecasesearchoutput>(strSPQuery, listParam);
return AcctLst;
}
Here also createCase is encountering await and
it should return immediately right and execute the very next line itself and print Async called
before even the SaveCaseSearch completes right ?
Okay if I am thinking loud it might be control returns to the caller .
So is it like if I wrap my call SavCaseSearch inside another async/await method named suppose
async DoWork() {....
}
and call this DoWork() from CreateCase() directly so then
It will go on printing "Async called" once call to DoWork() encounters await and before it even completes ?
Am I thinking in the correct way ?
Also sometimes I see and get confused between
await someAsync()
and
await Task.Run(() => someAsync()) ..
what's the difference between them ? and which one to follow ?
My question is in my application :
Your code won't compile because you're using await without async. Corrected code would be:
public async Task<IList<createcaseoutput>> createCaseAsync(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)
{
...
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
console.writeline("Async called");
return AcctLst;
}
Here also createCase is encountering await and it should return immediately right and execute the very next line itself and print Async called before even the SaveCaseSearch completes right ?
No. This code:
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
is the same as this code:
var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
await saveTask;
So, first, createCaseAsync would call saveCaseSearchAsync. Presumably, saveCaseSearchAsync is performing some asynchronous operation, so it will return an incomplete task to createCaseAsync. createCaseAsync then awaits that task, which causes it to return an incomplete task to its caller.
Eventually, saveCaseSearchAsync will complete, which will complete the task it returned (which I called saveTask in the code above). This in turn will continue executing createCaseAsync, and it will proceed to the next line and print "Async called" on the console.
So is it like if I wrap my call SavCaseSearch inside another async/await method
You wouldn't need a wrapper because createCaseAsync is already returning a Task.
what's the difference between them ? and which one to follow ?
Task.Run is mainly for pushing blocking work off the UI thread and onto the threadpool. Since you're on ASP.NET, don't use Task.Run.
The first rule of async is to always use async or never use async.
If your underlying API can't handle async it's no use to use async in the upper layers (like ASP.NET MVC), since at some point you'll get thread starvation as all threads are occupied waiting on IO operations (like DB calls).
Your example is a classical case where you mix sync and async. The Sleep call will lock the thread until it completes. You should have used Task.Delay instead as it would have released the thread until the delay completes.
My advice to you is to simply start by following the rule I mentioned first and only when IO bound operations like DB or file calls are involved. Then when you understand async better you can start to break it since you then have a much better understanding in what it can lead to.
(Sorry for not answering your questions directly, but threading is a complex topic and your brain can fry if you try to get it all in directly. Start small.)
Here also createCase is encountering await and it should return immediately right and execute the very next line itself and print Async called before even the SaveCaseSearch completes right ?
This shouldn't even compile. The 'await' operator can only be use within an 'async' method. That said, if you remove the 'await' operator, then the next line will print "Async called" before even the saveCaseSearch completes.
Am I thinking in the correct way ?
saveCaseSearch is already an 'async' method, so you don't need to wrap it to achieve the desired result. That said, you could wrap it in another method, if you really want to.
what's the difference between them ? and which one to follow ?
The 'await' operator wait for a Task object so either one is fine. I would chose await someAsync(), because it's less code to write.
Regarding the difference between async/await and Tasks...
Async/Await are syntactic keywords to simplify your code, as everything before the await keyword happens in the calling thread and everything from the await onward happens is in the task's continuation.
Setting this up with tasks using the TPL will require a lot of code and readability suffers. Note however, Underneath it is still using Tasks and Continuations.
Further, they cannot always be used in place of Tasks like when the completion of Task is nondeterministic, or if you have multiple levels of Tasks along with the usage of TaskCompletionSource.
For more information read the chapter 4 "Asynchronous Programming" in the book "Writing High-Performance .NET Code" by Ben Watson
Note also, Internally, the TPL uses the .NET thread pool, but does so more intelligently, by executing multiple Tasks on the same thread sequentially before returning the thread back to the pool. It can do this via intelligent use of delegate objects.

Unexpected behaviour after returning from await

I know there are a lot of questions about async/await, but I couldn't find any answer to this.
I've encountered something I don't understand, consider the following code:
void Main()
{
Poetry();
while (true)
{
Console.WriteLine("Outside, within Main.");
Thread.Sleep(200);
}
}
async void Poetry()
{
//.. stuff happens before await
await Task.Delay(10);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Inside, after await.");
Thread.Sleep(200);
}
}
Obviously, on the await operator, the control returns to the caller, while the method being awaited, is running on the background. (assume an IO operation)
But after the control comes back to the await operator, the execution becomes parallel, instead of (my expectation) remaining single-threaded.
I'd expect that after "Delay" has been finished the thread will be forced back into the Poetry method, continues from where it left.
Which it does. The weird thing for me, is why the "Main" method keeps running? is that one thread jumping from one to the other? or are there two parallel threads?
Isn't it a thread-safety problem, once again?
I find this confusing. I'm not an expert. Thanks.
I have a description on my blog of how async methods resume after an await. In essence, await captures the current SynchronizationContext unless it is null in which case it captures the current TaskScheduler. That "context" is then used to schedule the remainder of the method.
Since you're executing a Console app, there is no SynchronizationContext, and the default TaskScheduler is captured to execute the remainder of the async method. That context queues the async method to the thread pool. It is not possible to return to the main thread of a Console app unless you actually give it a main loop with a SynchronizationContext (or TaskScheduler) that queues to that main loop.
Read It's All About the SynchronizationContext and I'm sure it'll become less confusing. The behavior you're seeing makes perfect sense. Task.Delay uses Win32 Kernel Timer APIs internally (namely, CreateTimerQueueTimer). The timer callback is invoked on a pool thread, different from your Main thread. That's where the rest of Poetry after await continues executing. This is how the default task scheduler works, in the absence of synchronization context on the original thread which initiated the await.
Because you don't do await the Poetry() task (and you can't unless you return Task instead of void), its for loop continues executing in parallel with the while loop in your Main. Why, and more importantly, how would you expect it to be "forced" back onto the Main thread? There has to be some explicit point of synchronization for this to happen, the thread cannot simply get interrupted in the middle of the while loop.
In a UI application, the core message loop may serve as such kind of synchronization point. E.g. for a WinForms app, WindowsFormsSynchronizationContext would make this happen. If await Task.Delay() is called on the main UI thread, the code after await would asynchronously continue on the main UI thread, upon some future iteration of the message loop run by Application.Run.
So, if it was a UI thread, the rest of the Poetry wouldn't get executed in parallel with the while loop following the Poetry() call. Rather, it would be executed when the control flow had returned to the message loop. Or, you might explicitly pump messages with Application.DoEvents() for the continuation to happen, although I wouldn't recommend doing that.
On a side note, don't use async void, rather use async Task, more info.
When you call an async routine the purpose of this is to allow the program to run a method while still allowing the calling routine, form or application to continue to respond to user input (in other words, continue execution normally). The "await" keyword pauses execution at the point it is used, runs the task using another thread then returns to that line when the thread completes.
So, in your case if you want the main routine to pause until the "Poetry" routine is done you need to use the await keyword something like this:
void async Main()
{
await Poetry();
while (true)
{
Console.WriteLine("Outside, within Main.");
Thread.Sleep(200);
}
}
You will also need to change the definition for Poetry to allow the await keyword to be used:
async Task Poetry()
Because this question really intrigued me I went ahead and wrote an example program you can actually compile. Just create a new console application and paste this example in. You can see the result of using "await" versus not using it.
class Program
{
static void Main(string[] args)
{
RunMain();
// pause long enough for all async routines to complete (10 minutes)
System.Threading.Thread.Sleep(10 * 60 * 1000);
}
private static async void RunMain()
{
// with await this will pause for poetry
await Poetry();
// without await this just runs
// Poetry();
for (int main = 0; main < 25; main++)
{
System.Threading.Thread.Sleep(10);
Console.WriteLine("MAIN [" + main + "]");
}
}
private static async Task Poetry()
{
await Task.Delay(10);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("IN THE POETRY ROUTINE [" + i + "]");
System.Threading.Thread.Sleep(10);
}
}
}
Happy testing! Oh, and you can still read more information here.
I'd like to answer my own question here.
Some of you gave me great answers which all helped me understand better (and were thumbed up). Possibly no one gave me a full answer because I've failed to ask the full question. In any case someone will encounter my exact misunderstanding, I'd like this to be the first answer (but I'll recommend to look at some more answers below).
So, Task.Delay uses a Timer which uses the operating system to fire an event after N milliseconds. after this period a new pooled thread is created, which basically does almost nothing.
The await keyword means that after the thread has finished (and it's doing almost nothing) it should continue to whatever comes after the await keyword.
Here comes the synchronization context, as mentioned in other answers.
If there is no such context, the same newly-created-pooled-thread will continue running what ever comes after the await.
If there is a synchronizing context, the newly-created-pool-thread, will only push whatever comes after the await, into synchronizing context.
For the sake of it, here are a few points I didn't realize:
The async/await are not doing anything which wasn't (technologly speaking) possible before. Just maybe amazingly clumsy.
It's is just a language support for some of .NET 4.5 classes.
It's much like yield return. It may break your method into a few methods, and may even generate a class behind, and use some methods from the BCL, but nothing more.
Anyway, I recommend reading C# 5.0 In A Nutshell's chapter "Concurrency and Asynchrony". It helped me a lot. It is great, and actually explains the whole story.

Categories