Say in button click event I have:
await someFn()
And in the someFn code, I have got some synchronous code and some asynchronous code.
As per online reading on this topic, they all seem to say that when await is encountered, control immediately goes back the caller (UI thread in this case) while the asynchronous waiting happens.
I haven't come across situation where it is explained what happens when there is some synchronous code just before the async code in the awaited function. Does the synchronous code execute before passing the control to the caller (UI thread)?
I know that- had it been run using await Task.Run(...) instead of await someFn() then it would execute in a separate thread.
It is true that "when await is encountered, control immediately goes back the caller", under the condition that the awaitable will not be completed at the await point. Otherwise (if the awaitable is already completed) the control will stay inside the method, by executing immediately the code that follows the await.
That's all that influences the behavior of the await operator: the result of the IsCompleted property of the awaiter. It doesn't matter if the method that produced the awaitable included synchronous code or not. The await doesn't know, and doesn't care. A synchronous code block inside the someFn will indeed make a difference regarding the responsiveness of your application, but that has nothing to do with the await. To understand why, it may help to rewrite your code in a more verbose but equivalent form. This:
await someFn();
...is equivalent to this:
Task t = someFn();
await t;
The UI of your application will freeze because the someFn() blocks, not because the await t blocks. Unless of course you have created some wicked task-like awaitable type, that blocks when the IsCompleted property of its awaiter is invoked.
If you see an await in your code, for example when you see var obj = await someFn();, then you can treat is as a placeholder for the following code:
var waitingTask task = someFn();
if (!task.IsCompleted) {
var thisTask = [Magic]
return thisTask.Task;
}
var obj = waitingTask.Result;
In reality the code is rewritten to something more complex, a so called state machine. The [Magic] part is hard to explain but what it does is capturing the current SynchronizationContext, the current line that is executing and the task it's waiting on.
As soon as the task that you are waiting on completes, it will try to restore this method on the captured SynchronizationContext and continue working. It's this SynchronizationContext that tells you if you are working on the UI thread or not. This is why it's advised to use ConfigureAwait(false) to avoid restoring on the UI thread if it's not needed, avoiding possible slow downs on the UI for executing code that does nothing with the UI.
The main point here is that you see that the code before an await is executed synchronously/immediately. Even the code inside the function that you are calling is executed synchronously/immediately until you reach an await in that function that is not completed. From this point on the stack 'rewinds', creating (returning) a new Task on each point that waits for the underlying code to complete. If the lowest task completes, only that task that waits for it is 'revived', all tasks above it still stay 'waiting' and only when that bottom function has reached it real end of the method will it 'revive' the task that is waiting for it's result, and so on to the top of the stack.
Related
I have a WinForms application with a single button and a single button Click event handler. In the event handler, I have this code:
NOTE: DoWorkAsync() returns a Task<int>.
var result = obj.DoWorkAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Implementation of DoWorkAsync():
public async Task<int> DoWorkAsync()
{
await Task.Delay(3000);
return 200;
}
This code will deadlock but I am not sure why. I have configured the task not to continue on the UI thread after GetResult() returns. So why does the code deadlock instead of running the next line of code?
I have configured the task
ConfigureAwait is for configuring awaits, not tasks. There's nothing that awaits the result of the ConfigureAwait, so that's an indication that it's being misused here.
I have configured the task not to continue on the UI thread after GetResult() returns.
Not really. As explained above, the ConfigureAwait has no effect here. More broadly, the code is (synchronously) blocking on the task, so the UI thread is blocked and then will resume executing after GetResult() returns.
This code will deadlock but I am not sure why.
Walk through it step by step. Read my blog post on async/await if you haven't already done so.
Note that this:
var result = obj.DoWorkAsync().ConfigureAwait(false).GetAwaiter().GetResult();
is pretty much the same as this:
var doWorkTask = obj.DoWorkAsync();
var result = doWorkTask.ConfigureAwait(false).GetAwaiter().GetResult();
Asynchronous methods begin executing synchronously, just like any other method. In this case, DoWorkAsync is called on the UI thread.
DoWorkAsync calls Task.Delay (also synchronously).
Task.Delay returns a task that is not complete; it will complete in 3 seconds. Still synchronous, and on the UI thread.
The await in DoWorkAsync checks to see if the task is complete. Since it is not complete, await captures the current context (the UI context), pauses the method, and returns an incomplete task.
The calling code calls ConfigureAwait(false) on the returned task. This essentially has no effect.
The calling code calls GetAwaiter().GetResult() on the (configured) returned task. This blocks the UI thread waiting on the task.
3 seconds later, the task returned by Task.Delay completes, and the continuation of DoWorkAsync is scheduled to the context captured by its await - the UI context.
Deadlock. The continuation is waiting for the UI thread to be free, and the UI thread is waiting for the task to complete.
In summary, a top-level ConfigureAwait(false) is insufficient. There are several approaches to sync-over-async code, with the ideal being "don't do it at all; use await instead". If you want to directly block, you need to apply ConfigureAwait(false) on every await on the method that is called (DoWorkAsync in this case), as well as the transitive closure of all methods called starting from there.
Clearly, this is a maintenance burden, and occasionally impossible (i.e., third-party libraries missing a ConfigureAwait(false)), and that's why I don't usually recommend this approach.
I was reading this article and found this example:
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
delayTask.Wait();
}
}
The root cause of this deadlock is due to the way await handles contexts. By default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. This “context” is the current SynchronizationContext unless it’s null, in which case it’s the current TaskScheduler. GUI and ASP.NET applications have a SynchronizationContext that permits only one chunk of code to run at a time. When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete. They’re each waiting for the other, causing a deadlock.
I understand that if there was code after await Task.Delay(1000);, it would be part of the continuation, and that continuation would be running in the same context as Test(), and that's how the deadlock would happen.
However, there is no continuation, so how does the deadlock actually happen?
Or, is there an empty continuation that is created? What would be the point in that?
This is the part that is confusing me:
When the await completes, it attempts to execute the remainder of the
async method within the captured context.
What is the "remainder of the async method"?
If we're an async Task or async Task<T> method, then there's always work to do after the await - we need to ensure that any exception produced by the awaited task is properly propagated to our own Task, or that we pass the appropriate normal return value through.
If we're any kind of async method using structures such as using which insert compiler-generated code at the end of an otherwise appearing empty epilogue to our method, then we'll be inserting code at the end of the method, even if it doesn't appear in the source.
If we're any normal async method that liberally uses awaits then we'll already have a state machine built and running to execute our method and there's no point in optimizing the "no code after the last await" possibility.
In the narrow case that we're an async void1 method that contains a single await at the end, then other than some minutiae about where an unhandled exception from a task might be reported, we already had the opportunity to avoid excess code generation by not making the method async at all and just ignoring the awaitable.
So there's no reason to try to optimize this situation.
1We're already in a state of sin at that point anyway.
I am using async method as extension for StorageFile to return file's size. Problem is, this method deadlocks somehow my Windows Store app. Issue is within awaiting result from file.GetBasicPropertiesAsync. I am not very experienced in asynchronous programming, but I supposed await statement is there to prevent such situations. Does anyone see something obvious what I don't get?
Deadlock do not occur in debug, if I wait for some time with GetBasicPropertiesAsync.
Method:
public static async Task<string> GetSizeMB(this StorageFile file)
{
var properties = await file.GetBasicPropertiesAsync();
double sizeDouble = Convert.ToDouble(properties.Size) /1000000;
return $"{Math.Round(sizeDouble, 2)} MB";
}
Thanks in advance for hints.
If you look further up your call stack, you're almost certainly calling a task's Result or Wait member from the UI thread. This is not permitted on Windows Store applications, since it can freeze the UI thread.
I describe this kind of deadlock in detail on my blog, but the summary version is as follows:
When await has to (asynchronously) wait, by default it will first capture a "context". This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. Later, when the (asynchronous) wait is complete, the remainder of your async method continues executing on that captured context.
In this case, the context is the UI SynchronizationContext. Further up your call stack, another method calls GetSizeMB and gets back a task, and then (presumably) calls Result or Wait on that task. This is the actual cause of the deadlock, because that code is blocking the UI thread until GetSizeMB completes. But GetSizeMB cannot complete because it needs to resume executing on the UI thread.
The proper fix is to replace Result/Wait with await.
In this code:
public async Task v_task()
{
await Task.Run(() => Console.WriteLine("Hello!"));
}
public async void v1()
{
await v_task();
// some other actions...
}
public void ButtonClick()
{
v1();
Console.WriteLine("Hi!");
}
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
I mean, what should be my concerns about race conditions working with async/await? All async methods are mandatory executed in the same caller's thread? Should I use mutex on possible shared state? If yes, how could I detect what are the shared state objects?
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
Only the Console.WriteLine within the Task.Run.
I mean, what should be my concerns about race conditions working with async/await?
I suggest you start by reading my async intro, which explains how await actually works.
In summary, async methods are usually written in a serially asynchronous fashion. Take this code for example:
CodeBeforeAwait();
await SomeOtherMethodAsync();
CodeAfterAwait();
You can always say that CodeBeforeAwait will execute to completion first, then SomeOtherMethodAsync will be called. Then our method will (asynchronously) wait for SomeOtherMethodAsync to complete, and only after that will CodeAfterAwait be called.
So it's serially asynchronous. It executes in a serial fashion, just like you'd expect it to, but also with an asynchronous point in that flow (the await).
Now, you can't say that CodeBeforeAwait and CodeAfterAwait will execute within the same thread, at least not without more context. await by default will resume in the current SynchronizationContext (or the current TaskScheduler if there is no SyncCtx). So, if the sample method above was executed in the UI thread, then you would know that CodeBeforeAwait and CodeAfterAwait will both execute on the UI thread. However, if it was executed without a context (i.e., from a background thread or Console main thread), then CodeAfterAwait may run on a different thread.
Note that even if parts of a method run on a different thread, the runtime takes care of putting any barriers in place before continuing the method, so there's no need to barrier around variable access.
Also note that your original example uses Task.Run, which explicitly places work on the thread pool. That's quite different than async/await, and you will definitely have to treat that as multithreaded.
Should I use mutex on possible shared state?
Yes. For example, if your code uses Task.Run, then you'll need to treat that as a separate thread. (Note that with await, it's a lot easier to not share state at all with other threads - if you can keep your background tasks pure, they're much easier to work with).
If yes, how could I detect what are the shared state objects?
Same answer as with any other kind of multi-threaded code: code inspection.
If you call an async function, your thread will perform this function until it reaches an await.
If you weren't using async-await, the thread would yield processing until the awaited code was finished and continue with the statement after the await.
But as you are using async-await, you told the compiler that whenever the thread has to wait for something, you have some other things it can do instead of waiting, The thread will do those other things until you say: now await until your original thing is finished.
Because of the call to an async function we are certain that somewhere inside there should be an await. Note that if you call an async function that doesn't await you get a compiler warning that the function will run synchronously.
Example:
private async void OnButton1_clickec(object sender, ...)
{
string dataToSave = ...;
var saveTask = this.MyOpenFile.SaveAsync(dataToSave);
// the thread will go into the SaveAsync function and will
// do all things until it sees an await.
// because of the async SaveAsync we know there is somewhere an await
// As you didn't say await this.MyOpenfile.SaveAsync
// the thread will not wait but continue with the following
// statements:
DoSomethingElse()
await saveTask;
// here we see the await. The thread was doing something else,
// finished it, and now we say: await. That means it waits until its
// internal await is finished and continues with the statements after
// this internal await.
Note that even if the await somewhere inside SaveAsync was finished, the thread will not perform the next statement until you await SaveTask. This has the effect that DoSomethingElse will not be interrupted if the await inside the SaveAsync was finished.
Therefore normally it's not useful to create an async function that does not return either a Task or a Task < TResult >
The only exception to this is an event handler. The GUI doesn't have to wait until your event handler is finished.
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.