I've read the advice many times from people smarter than me, and it has few caveats: Always use ConfigureAwait(false)
inside library code. So I'm fairly certain I know the the answer, but I want to be 100%. The scenario is I have a library that thinly wraps some other asynchronous library.
Library code:
public async Task DoThingAsyc() {
// do some setup
return await otherLib.DoThingAsync().ConfigureAwait(false);
}
Application code:
// need to preserve my synchronization context
await myLib.DoThingAync();
// do I have my context here or did my lib lose it?
If we set 'ConfigureAwait(true)' then the continuation task runs on the same thread used before the 'await' statement. If we set 'ConfigureAwait(false)' then the continuation task runs on the available thread pool thread.
If the await task. ConfigureAwait(false) involves a task that's already completed by the time it's awaited (which is actually incredibly common), then the ConfigureAwait(false) will be meaningless, as the thread continues to execute code in the method after this and still in the same context that was there previously.
ConfigureAwait(continueOnCapturedContext: false) is used to avoid forcing the callback to be invoked on the original context or scheduler. This has a few benefits: Improving performance.
To improve performance and avoid potential deadlocks, use ConfigureAwait(false) in any non-UI code. The exception here is app-level code, such as Windows Forms, WPF, and ASP.NET. ConfigureAwait(true) corresponds to the default behavior and does nothing meaningful, therefore such calls can be safely omitted.
No.
The capturing of the SynchronizationContext
happens on await
. ConfigureAwait
configures the specific await
.
If the application calls a library's async method and awaits it the SC is captured on the spot regardless of what happens inside the call.
Now, because the async method's synchronous part (which is the part before the first await
) is executed before a task is returned to be awaited, you can mess around with the SynchronizationContext
there, but ConfigureAwait
doesn't do that.
In your specific example you seem to be returning the result of ConfigureAwait
from the async method. That can't happen because ConfigureAwait
returns the ConfiguredTaskAwaitable
struct. If however we change the method return type:
public ConfiguredTaskAwaitable DoThingAsyc()
{
return otherLib.DoThingAsync().ConfigureAwait(false);
}
Then awaiting it will indeed affect the calling code's await behavior.
Example from http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx
... logically you can think of the following code:
await FooAsync(); RestOfMethod();
as being similar in nature to this:
var t = FooAsync(); var currentContext = SynchronizationContext.Current; t.ContinueWith(delegate { if (currentContext == null) RestOfMethod(); else currentContext.Post(delegate { RestOfMethod(); }, null); }, TaskScheduler.Current);
which means you should have your context back after the await myLib.DoThingAync();
call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With