-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Use ExecutionContext.Restore rather than EC.Run callback #37942
Conversation
Thanks, @benaadams. Any perf impact? |
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
11f08f2
to
a212991
Compare
Moved to using same api as would use externally.
Resolved |
For the common path (with no EC) can only see how it would get a little faster since the calls are inlined for that path. If |
4f96c49
to
b6b9436
Compare
Rebased |
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Show resolved
Hide resolved
36b7a5f
to
2c0c15c
Compare
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM other than my one comment. @kouvel, any concerns?
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
|
||
ExecutionContext? currentContext = ExecutionContext.Capture(); | ||
// Restore the captured ExecutionContext before executing anything. | ||
ExecutionContext.Restore(_executionContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to call this method Apply
or something similar instead of Restore
given how it's used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends on results of api review #38011
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would the ASP.NET use case of the public API not use EC.Run() instead? In any case even for a public API (which would be a somewhat advanced API that may be misused), Apply seems more appropriate to me, maybe something to consider in the API review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would the ASP.NET use case of the public API not use EC.Run() instead?
Because EC.Run forces you into a callback model, which is problematic if the code you're wrapping needs to be async.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm ok. Would a RunAsync instead be workable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not just the shape of the method: it's the overhead. A goal here is to avoid the extra machinery/allocation associated with another level of async method / state machine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, but if that's why we're exposing the API (for perf), then would it make sense to prefix the API name with Unsafe
or something else similarly since it feels like it could be easily misused?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm ok. Would a RunAsync instead be workable?
Well just putting it behind a regular async
method gives that effect.
The ASP.NET case is inlining all the await
s into a top level request loop (as its allocated once for all requests on the connection); however the loop calls user code, if any of the methods are not async (Task.CompletedTask
returning), but also change AsyncLocal<T>
s then they are not undone and those changes leak into the next request (dotnet/aspnetcore#15384, dotnet/aspnetcore#13991)
The .Restore method allows the EC to be captured as a hoisted var outside the loop; and then reset back at the end of each loop iteration so each new request starts on a fresh ExecutionContext throwing away any changes from the last iteration dotnet/aspnetcore#23175 (kinda like the ThreadPool does)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e.g.
var ec = ExecutionContext.Capture();
while (!cancelled)
{
await NextRequest();
await OnStartAsync(); // User code
await ProcessRequestAsync(); // User code
await OnCompleteAsync(); // User code
ExecutionContext.Restore(ec);
}
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs
Show resolved
Hide resolved
.../System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs
Show resolved
Hide resolved
69e582d
to
3895f53
Compare
Rebased to retrigger tests |
Good to merge? |
Thanks! |
Only running inline needs to do extra work and error handling for post run restore
@stephentoub this would be the change for
ManualResetValueTaskSourceCore
to useExecutionContext.Restore
rather than a genericref
passing callback basedExecutionContext.Run