According to best practices it is recommended to use .ConfigureAwait(false) with async/await keywords if you can:
await Task.Run(RunSomethingAsync).ConfigureAwait(false);
Can you please give me an example of a situation when I cannot use .ConfigureAwait(false)?
You "cannot" use ConfigureAwait(false) when you actually care about the synchronization context you're in. For example, imagine the following in a GUI application:
public async void SomeButtonClick(object sender, EventArgs e)
{
var result = await SomeAsyncOperation().ConfigureAwait(false);
textBox.Text = result;
}
When you return from ConfigureAwait, you wont be back on the UI thread. This will cause an InvalidOperationException.
From the source: Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects:
When you are awaiting on a method with await keyword, compiler
generates bunch of code in behalf of you. One of the purposes of this
action is to handle synchronization with the UI (or main) thread. The key
component of this feature is the SynchronizationContext.Current which
gets the synchronization context for the current thread.
SynchronizationContext.Current is populated depending on the
environment you are in. The GetAwaiter method of Task looks up for
SynchronizationContext.Current. If current synchronization context is
not null, the continuation that gets passed to that awaiter will get
posted back to that synchronization context.
When consuming a method, which uses the new asynchronous language
features, in a blocking fashion, you will end up with a deadlock if
you have an available SynchronizationContext. When you are consuming
such methods in a blocking fashion (waiting on the Task with Wait
method or taking the result directly from the Result property of the
Task), you will block the main thread at the same time. When
eventually the Task completes inside that method in the threadpool, it
is going to invoke the continuation to post back to the main thread
because SynchronizationContext.Current is available and captured. But
there is a problem here: the UI thread is blocked and you have a
deadlock!
Related
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.
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.
Given the following method as example:
private async void F()
{
button.IsEnabled = false;
await Task.Delay(1000);
button.IsEnabled = true;
}
In this case, any code starting at await always occurs on another thread (edit: wrong) which presumably should not have access to the UI thread, similarly to desktop apps. In a similar situation, I recall having an exception such as:
The application called an interface that was marshalled for a different thread.
However, the example does not trigger any exception. Is this expected? Can I reliably write code like this?
any code starting at await always occurs on another thread (non-UI thread, right?),
No, not at all. await does not kick off other threads. I have an async intro that may help if you find this statement confusing.
What await will do is schedule the remainder of the method as a continuation to be run after the asynchronous operation completes (in this case, the asynchronous operation is just a timer firing). By default, await will capture a "context", which is SynchronizationContext.Current (or, if it is null, the context is TaskScheduler.Current). In this case, there's a UI SynchronizationContext that ensures the remainder of the async method will run on the UI thread.
Code running on the UI thread has a SynchronizationContext. You can see that by printing SynchronizationContext.Current. Before you await something that context is captured and after the await your code resumes on that context which makes sure the continuation runs on the UI thread.
To get the behavior you're referencing, where the continuation is run on a ThreadPool thread you can disable the SynchronizationContext capturing by using ConfigureAwait(false):
private async void FooAsync()
{
button.IsEnabled = false;
await Task.Delay(1000).ConfigureAwait(false);
button.IsEnabled = true;
}
This code will raise the exception you expect.
Is this expected? Can I reliably write code like this?
Yes and yes. Code using async-await will "do the right thing" by default. But if you do want to offload something to a ThreadPool thread you can use Task.Run.
I've read (and used) async/await quite a lot for some time now but I still have one question I can't get an answer to. Say I have this code.
private async void workAsyncBtn_Click(object sender, EventArgs e)
{
var myTask = _asyncAwaitExcamples.DoHeavyWorkAsync(5);
await myTask;
statusTextBox.Text += "\r\n DoHeavyWorkAsync message";
}
It's called from the UI thread and returned to the UI Thread. Therefor I am able to do UI-specific things in this method and after the await myTask. If I had used .ConfigureAwait(false) I would get a thread exception when doing statusTextBox.Text += "\r\n DoHeavyWorkAsync message"; since I would have telled myTask it's ok to take any available thread from the thread pool.
My question. As I understand it I never leave the UI thread in this case, still it's run asynchronously, the UI is still responsive and I can start several Tasks at the same time and therefor speed up my application. How can this work if we only use one thread?
Thanks!
EDIT for Sievajet
private async void workAsyncBtn_Click(object sender, EventArgs e)
{
await DoAsync();
}
private async Task DoAsync()
{
await Task.Delay(200);
statusTextBox.Text += "Call to form";
await Task.Delay(200);
}
As I understand it I never leave the UI thread in this case, still
it's run asynchronously, the UI is still responsive and I can start
several Tasks at the same time and therefor speed up my application.
How can this work if we only use one thread?
First, i'd recommend reading Stephan Clearys blog post - There is no thread.
In order to understand how its possible to run multiple units of work altogether, we need to grasp one important fact: async IO bound operations have (almost) nothing to do with threads.
How is that possible? well, if we drill deep down all the way to the operating system, we'll see that the calls to the device drivers - those which are in charge of doing operations such as network calls and writing to disk, were all implemented as naturally asynchronous, they don't occupy a thread while doing their work. That way, while the device driver is doing its thing, there need not be a thread. only once the device driver completes its execution, it will signal the operating system that it's done via an IOCP (I/O completion port), which will then execute the rest of the method call (this is done in .NET via the threadpool, which has dedicated IOCP threads).
Stephans blog post demonstrates this nicely:
Once the OS executes the DPC (Deferred Procedure Call) and queue the IRP (I/O Request Packet), it's work is essentially done until the device driver signals it back with the I'm done messages, which causes a whole chain of operations (described in the blog post) to execute, which eventually will end up with invoking your code.
Another thing to note is that .NET does some "magic" for us behind the scenes when using async-await pattern. There is a thing called "Synchronization Context" (you can find a rather lengthy explanation here). This sync context is whats in-charge of invoking the continuation (code after the first await) on the UI thread back again (in places where such context exists).
Edit:
It should be noted that the magic with the synchronization context happens for CPU bound operations as well (and actually for any awaitable object), so when you use a threadpool thread via Task.Run or Task.Factory.StartNew, this will work as well.
The TaskParallelLibrary (TPL) uses a TaskScheduler which can be configured with TaskScheduler.FromCurrentSynchronizationContext to return to the SynchronizationContext like this :
textBox1.Text = "Start";
// The SynchronizationContext is captured here
Factory.StartNew( () => DoSomeAsyncWork() )
.ContinueWith(
() =>
{
// Back on the SynchronizationContext it came from
textBox1.Text = "End";
},TaskScheduler.FromCurrentSynchronizationContext());
When an async method suspends at an await, by default it will capture the current SynchronizationContext and marshall the code after the await back on the SynchronizationContext it came from.
textBox1.Text = "Start";
// The SynchronizationContext is captured here
/* The implementation of DoSomeAsyncWork depends how it runs, this could run on the threadpool pool
or it could be an 'I/O operation' or an 'Network operation'
which doesnt use the threadpool */
await DoSomeAsyncWork();
// Back on the SynchronizationContext it came from
textBox1.Text = "End";
async and await example:
async Task MyMethodAsync()
{
textBox1.Text = "Start";
// The SynchronizationContext is captured here
await Task.Run(() => { DoSomeAsyncWork(); }); // run on the threadPool
// Back on the SynchronizationContext it came from
textBox1.Text = "End";
}
When UI thread calls await it starts the async operation and returns immediately. When the async operation completes, it notifies a thread from the thread pool but the internal implementation of async await dispatches the execution to the UI thread which will continue the execution of the code after the await.
The Dispatch is implemented by means of SynchronizationContext which in turn calls System.Windows.Forms.Control.BeginInvoke.
CLR via C# (4th Edition) (Developer Reference) 4th Edition by Jeffrey Richter page 749
Actually, Jeffrey worked with MS to implement the async/await inspired by his AsyncEnumerator
This article from states that SynchronizationContext may flow with ExecutionContext:
private void button1_Click(object sender, EventArgs e) {
button1.Text = await Task.Run(async delegate
{
string data = await DownloadAsync();
return Compute(data);
});
}
Here’s what my mental model tells me will happen with this code. A
user clicks button1, causing the UI framework to invoke button1_Click
on the UI thread. The code then kicks off a work item to run on the
ThreadPool (via Task.Run). That work item starts some download work
and asynchronously waits for it to complete. A subsequent work item
on the ThreadPool then does some compute-intensive operation on the
result of that download, and returns the result, causing the Task that
was being awaited on the UI thread to complete. At that point, the UI
thread processes the remainder of this button1_Click method, storing
the result of the computation into the button1’s Text property.
My expectation is valid if SynchronizationContext doesn’t flow as part
of ExecutionContext. If it does flow, however, I will be sorely
disappointed. Task.Run captures ExecutionContext when invoked, and
uses it to run the delegate passed to it. That means that the UI
SynchronizationContext which was current when Task.Run was invoked
would flow into the Task and would be Current while invoking
DownloadAsync and awaiting the resulting task. That then means that
the await will see the Current SynchronizationContext and Post the
remainder of asynchronous method as a continuation to run back on the
UI thread. And that means my Compute method will very likely be
running on the UI thread, not on the ThreadPool, causing
responsiveness problems for my app.
The story now gets a bit messier: ExecutionContext actually has two Capture methods, but
only one of them is public. The internal one (internal to mscorlib)
is the one used by most asynchronous functionality exposed from
mscorlib, and it optionally allows the caller to suppress the
capturing of SynchronizationContext as part of ExecutionContext;
corresponding to that, there’s also an internal overload of the Run
method that supports ignoring a SynchronizationContext that’s stored
in the ExecutionContext, in effect pretending one wasn’t captured
(this is, again, the overload used by most functionality in mscorlib).
What this means is that pretty much any asynchronous operation whose
core implementation resides in mscorlib won’t flow
SynchronizationContext as part of ExecutionContext, but any
asynchronous operation whose core implementation resides anywhere else
will flow SynchronizationContext as part of ExecutionContext. I
previously mentioned that the “builders” for async methods were the
types responsible for flowing ExecutionContext in async methods, and
these builders do live in mscorlib, and they do use the internal
overloads… as such, SynchronizationContext is not flowed as part of
ExecutionContext across awaits (this, again, is separate from how task
awaiters support capturing the SynchronizationContext and Post’ing
back to it). To help deal with the cases where ExecutionContext does
flow SynchronizationContext, the async method infrastructure tries to
ignore SynchronizationContexts set as Current due to being flowed.
However it isn't exactly clear to me when this might happen. It appears that it will happen when the public ExecutionContext.Capture method is used and the internal Task.Run overload that suppresses flowing SynchronizationContext with ExecutionContext is not used, but I don't know when that would be.
In my testing on .NET 4.5 Task.Run does not seem to flow the SynchronizationContext with the ExecutionContext:
private async void button1_Click(object sender, EventArgs e) {
Console.WriteLine("Click context:" + SynchronizationContext.Current);
button1.Text = await Task.Run(async delegate {
// In my tests this always returns false
Console.WriteLine("SynchronizationContext was flowed: " + (SynchronizationContext.Current != null));
string data = await DownloadAsync();
return Compute(data);
});
}
So my question is under what circumstances will Compute() be run on the UI context (blocking the UI thread) as discussed in the article?
When does Task.Run flow SynchronizationContext with ExecutionContext?
Never.
The point of that article is that (the public API for) flowing ExecutionContext will flow SynchronizationContext. But Task.Run (and "pretty much any asynchronous operation whose core implementation resides in mscorlib") will never do this.
The paragraph starting with "My expectation is valid if" is hypothetical. He's describing what would happen if Task.Run use the public API for flowing ExecutionContext. This would cause problems if it did this. That's why it doesn't ever do this.