Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do ConfigureAwait(false) #10164

Closed
divega opened this issue Oct 26, 2017 · 13 comments · Fixed by #21110
Closed

Do ConfigureAwait(false) #10164

divega opened this issue Oct 26, 2017 · 13 comments · Fixed by #21110
Assignees
Labels
area-global breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-3.0 type-enhancement
Milestone

Comments

@divega
Copy link
Contributor

divega commented Oct 26, 2017

Creating an issue so that we can chat about this, and decide (again) whether we should be doing anything differently.

See aspnet/SignalR#545 for some context. This was found by @anpete while trying to understand what Npgsql is doing around it.

We came to what we have (practically not doing anything) through a long and painful analysis, but unfortunately it is very hard (for me at least) to remember or find exactly what we decided.

@anpete
Copy link
Contributor

anpete commented Oct 26, 2017

@davidfowl @roji It would be great to get your perspectives on this.

@roji
Copy link
Member

roji commented Oct 29, 2017

For the Npgsql perspective... In general, libraries need run with a null synchronization context to allow their code to execute on the thread pool (and not, say, to be restricted to UI thread). Npgsql originally had ConfigureAwait(false) on every async single method invocation in the codebase; apart from being very cluttered, I had a more serious issue with ConfigureAwait(false).

There's actually a path inside Npgsql where code needs to execute on a special internal thread (to avoid a dependency on the threadpool, which sometimes creates deadlocks). In order to force this code to callback onto this internal thread, a special sync context is used (see SingleThreadSynchronizationContext.cs in case you're interested). This led to an odd situation: I need to be able to run the same code, sometimes with sync context null (the normal case) and sometimes with my own special sync context (the special case), but if you put ConfigureAwait(false) your sync context is always null. The solution I came up with was to set the sync context to null only at the user-facing public API methods, and then simply await down the stack without any need for ConfigureAwait(false). In effect, this removes the decision of which sync context is required from each individual method. Thanks to @anpete I just committed a new technique which is both safe and allocation-free, but you must take care to use it only from non-async top-level methods which wrap your async methods.

Note that the need to run the same methods with both sync context null and a specific sync context seems quite unique to Npgsql and I don't expect many other libraries to require this (I can elaborate on the Npgsql issue if you're interested). It does clean up lots of ConfigureAwait(false) in the codebase though :)

Let me know if you want any more info.

@ajcvickers
Copy link
Member

This was discussed in triage with the following conclusions:

  • EF calls into user code. This makes it more important the the context is preserved.
    • We could be selective and avoid the overhead on some low-level paths
  • Deadlocks was not a major concern because they only happen when .Wait is used, and this is bad practice anyway
  • Perf overhead was measured to be small
    • Perf overhead might be significant in tight loops, but these are a lot slower in async anyway, so it's not clear that it is worth doing anything here--but see idea above that we could change selected low-level paths
    • If async gets generally faster, then the relative perf gain could become more

Overall, we are not going to do anything immediately or generally on this, but based on other perf testing we could look at making targeted changes.

@davidfowl
Copy link
Member

@ajcvickers are you currently doing ConfigureAwait everywhere in the code base?

@ajcvickers
Copy link
Member

@davidfowl No, we don't call ConfigureAwait--that's what this discussion is about.

@davidfowl
Copy link
Member

But it's closed now 😄 . Are we going to?

@bricelam
Copy link
Contributor

@davidfowl No, we'll stick with our original decision to not call it. (reasoning above)

@davidfowl
Copy link
Member

I'm not sure those points are all entirely reasonable. How did you test the performance differences? What sync context did you use?

Deadlocks was not a major concern because they only happen when .Wait is used, and this is bad practice anyway

That's not true. If there's a sync context that serializes execution of continuations (like ASP.NET does) and you have 2 tasks that are interdependent then it's possible to cause a deadlock without explicitly calling .Wait.

It's not always about performance, it might actually be about correctness.

@ajcvickers
Copy link
Member

We held a new referendum on this issue. The outcome from this "People's Vote" is that we're going to do it. The sync context concerns are much less significant for .NET Core, and .NET Core is the future.

@ajcvickers ajcvickers reopened this Jan 24, 2019
@ajcvickers ajcvickers added this to the 3.0.0 milestone Jan 24, 2019
@ajcvickers ajcvickers self-assigned this Jan 24, 2019
@roji
Copy link
Member

roji commented Jan 25, 2019

@ajcvickers I can take this.

@ajcvickers
Copy link
Member

Go for it!

@ajcvickers
Copy link
Member

Removing milestone to discuss punting.

@ajcvickers ajcvickers removed this from the 3.0.0 milestone Jun 25, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0, Backlog Jun 27, 2019
@ajcvickers ajcvickers changed the title Re-discuss how we handle syncronization context (e.g. ConfigureAwait(false) or similar) Do ConfigureAwait(false) Nov 16, 2019
@ajcvickers ajcvickers modified the milestones: Backlog, 5.0.0 Nov 16, 2019
@ajcvickers
Copy link
Member

Closing in favor of #10164

@ajcvickers ajcvickers reopened this Nov 16, 2019
roji added a commit that referenced this issue Jun 2, 2020
Set up Microsoft.CodeAnalysis.FxCopAnalyzers with only the
ConfigureAwait rule enabled.

Closes #10164
@roji roji added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. breaking-change labels Jun 2, 2020
roji added a commit that referenced this issue Jun 2, 2020
Set up Microsoft.CodeAnalysis.FxCopAnalyzers with only the
ConfigureAwait rule enabled.

Closes #10164
roji added a commit that referenced this issue Jun 9, 2020
Set up Microsoft.CodeAnalysis.FxCopAnalyzers with only the
ConfigureAwait rule enabled.

Closes #10164

(cherry picked from commit e1c9a3a)
@ajcvickers ajcvickers modified the milestones: 5.0.0, 5.0.0-preview6 Jun 9, 2020
roji added a commit that referenced this issue Jun 9, 2020
Set up Microsoft.CodeAnalysis.FxCopAnalyzers with only the
ConfigureAwait rule enabled.

Closes #10164

(cherry picked from commit e1c9a3a)
wtgodbe pushed a commit that referenced this issue Jun 9, 2020
* [release/5.0-preview6] Update dependencies from dotnet/arcade (#21111)

* Update dependencies from https://github.com/dotnet/arcade build 20200530.1

Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Helix.Sdk
 From Version 5.0.0-beta.20261.9 -> To Version 5.0.0-beta.20280.1

* [master] Update dependencies from dotnet/arcade (#21091)

* Update dependencies from https://github.com/dotnet/arcade build 20200528.4

Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Helix.Sdk
 From Version 5.0.0-beta.20261.9 -> To Version 5.0.0-beta.20278.4

* Update dotnet on helix

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Brennan <brecon@microsoft.com>

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Brennan <brecon@microsoft.com>

* Return ValueTask in loggers and interceptors (#21152) (#21158)

Closes #21109

(cherry picked from commit 9f316e5)

* Add ConfigureAwait(false) (#21110) (#21185)

Set up Microsoft.CodeAnalysis.FxCopAnalyzers with only the
ConfigureAwait rule enabled.

Closes #10164

(cherry picked from commit e1c9a3a)

Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Brennan <brecon@microsoft.com>
Co-authored-by: Shay Rojansky <roji@roji.org>
@ajcvickers ajcvickers modified the milestones: 5.0.0-preview6, 5.0.0 Nov 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-global breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-3.0 type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants