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.
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.
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.
I'm trying to find out which approach is better let's say we have a button, after user clicks it we perform 1. Send a async request using httpClient
2. Some heavy synchronous staff like computations and saving data to a database.
Like that:
button1.Click += async(sender, e) =>
{
bool a = await Task.Run(async () => { return await MyTask1();});
}
async Task<bool> MyTask1()
{
await new HttpClient().GetAsync("https://www.webpage.com");
DoHeavyStuffFor5minutes();
return true;
}
button2.Click += async(sender, e) =>
{
bool a = await MyTask2();
}
async Task<bool> MyTask2()
{
await new HttpClient().GetAsync("https://www.webpage.com").ConfigureAwait(false);
DoHeavyStuffFor5minutes();
}
From what i understand GetAsync does not block my UI thread because underneath it uses a method which make it runs on different thread perhaps Task.Run or any other method that allows that.
But DoHeavyStuffFor5Minutes will block my UI because it will get called on the caller SynchornizationContext.
So i read that using ConfigureAwait(false) will make code after GetAsync do not run on the same SynchornizationContext as the caller. My question is, which approach is better first or the second one?
There is no need to execute HttpClient.GetAsync on a background thread using Task.Run since the HTTP request is truly asynchronous by nature so in this case your second approach is better that the first one.
When the Task returned by GetAsync has eventually finished, the remainder or MyTask2() will be executed on a thread pool thread assuming you opt out of capturing the context by calling ConfigureAwait(false).
Note however that ConfigureAwait(false) does not guarantee that the callback or remainer won't be run in the original context in all cases.
From Stephen Toub's blog post:
Does ConfigureAwait(false) guarantee the callback won’t be run in the original context?
"No. It guarantees it won’t be queued back to the original contex...but that doesn’t mean the code after an await task.ConfigureAwait(false) won’t still run in the original context. That’s because awaits on already-completed awaitables just keep running past the await synchronously rather than forcing anything to be queued back. So, if you await a task that’s already completed by the time it’s awaited, regardless of whether you used ConfigureAwait(false), the code immediately after this will continue to execute on the current thread in whatever context is still current."
So you might want to off-load DoHeavysTuffFor5minutes, which I assume is a CPU-bound and potentially long-running operation, to a background thread using Task.Run to be on the safe side. At least in the general case.
Also note that a method that is named *Async and returns a Task or Task<T> might still block the calling thread depending on its implementation. In general, this may be a reason to use your first approach of a calling both methods on a background thread in order to avoid blocking the UI thread. If you however use well-implemented APIs, such as HttpClient, this isn't an issue though.
EDIT
I took Jon's comment and retried the whole thing. And indeed, it is blocking the UI thread. I must have messed up my initial test somehow. The string "OnResume exits" is written after SomeAsync has finished. If the method is changed to use await Task.WhenAll(t) it will (as expected) not block. Thanks for the input!
I was first thinking about deleting the question because the initial assumption was just wrong but I think the answers contains valuable information that should not be lost.
The original post:
Trying to understand the deeper internals of async-await. The example below is from an Android app using Xamarin. OnResume() executes on the UI thread.
SomeAsync() starts a new task (= it spawns a thread). Then it is using Task.WaitAll() to perform a blocking wait (let's not discuss now if WhenAll() would be a better option).
I can see that the UI is not getting blocked while Task.WaitAll() is running. So SomeAsync() does not run on the UI thread. This means that a new thread was created.
How does the await "know" that it has to spawn a thread here - will it always do it? If I change the WaitAll() to WhenAll(), there would not be a need for an additional thread as fast as I understand.
// This runs on the UI thread.
async override OnResume()
{
// What happens here? Not necessarily a new thread I suppose. But what else?
Console.WriteLine ("OnResume is about to call an async method.");
await SomeAsync();
// Here we are back on the current sync context, which is the UI thread.
SomethingElse();
Console.WriteLine ("OnResume exits");
}
Task<int> SomeAsync()
{
var t = Task.Factory.StartNew (() => {
Console.WriteLine("Working really hard!");
Thread.Sleep(10000);
Console.WriteLine("Done working.");
});
Task.WhenAll (t);
return Task.FromResult (42);
}
Simple: it never spawns a thread for await. If the awaitable has already completed, it just keeps running; if the awaitable has not completed, it simply tells the awaitable instance to add a continuation (via a fairly complex state machine). When the thing that is being completed completes, that will invoke the continuations (typically via the sync-context, if one - else synchronously on the thread that is marking the work as complete). However! The sync-context could theoretically be one that chooses to push things onto the thread-pool (most UI sync-contexts, however, push things to the UI thread).
I think you will find this thread interesting: How does C# 5.0's async-await feature differ from the TPL?
In short, await does not start any threads.
What it does, is just "splitting" the code into at the point where the, let's say, line where 'await' is placed, and everything that that line is added as continuation to the Task.
Note the Task. And note that you've got Factory.StartNew. So, in your code, it is the Factory who actually starts the task - and it includes placing it on some thread, be it UI or pool or any other task scheduler. This means, that the "Task" is usually already assigned to some scheduler when you perform the await.
Of course, it does not have to be assigned, nor started at all. The only important thing is that you need to have a Task, any, really.
If the Task is not started - the await does not care. It simply attaches continuation, and it's up to you to start the task later. And to assign it to proper scheduler.
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.