Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Scheduler improvements #2026

Merged
merged 5 commits into from
Jan 11, 2018
Merged

Scheduler improvements #2026

merged 5 commits into from
Jan 11, 2018

Conversation

benaadams
Copy link
Member

@benaadams benaadams commented Jan 6, 2018

Scheduler Devirtualization

  • Seal internal types TaskRunScheduler and InlineScheduler
  • Maintain shared TaskRunScheduler and InlineScheduler in derived typed members; rather than base type
  • Expose via base type property that will devirtualize on inlining when the Jit sees the derived types (as type is maintained above, and derived type is sealed) JIT: improve return types in cases with spill temps coreclr#15766

Resolves: #2027

Fast Fire-and-Forget Tasks for TaskRunScheduler

  • Queue directly to ThreadPool; when available, rather than have the extra overhead of a Task which is ignored.
  • On netcoreapp2.1 use QueueUserWorkItem(preferLocal: true) which is lower contention and more closely matches Task behaviour dotnet/corefx#12442
  • If the Action fails create a failed Task so it can be captured as an unobserved task exception as per Task.Run

Resolves: #2002

Rename TaskRun -> ThreadPool #2026 (review)

/cc @davidfowl @pakrym

@benaadams
Copy link
Member Author

myget seems unhappy

21:23:12   Retrying 'FindPackagesByIdAsyncCore' for source 'https://dotnet.myget.org/F/dotnet-corefxlab/FindPackagesById()?id='Microsoft.NETCore.Compilers''.
21:23:12   Response status code does not indicate success: 503 (Service Unavailable).

@benaadams benaadams mentioned this pull request Jan 6, 2018
private static TaskRunScheduler _taskRunScheduler = new TaskRunScheduler();
private static InlineScheduler _inlineScheduler = new InlineScheduler();

public static Scheduler TaskRun => _taskRunScheduler;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThreadPool

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@benaadams
Copy link
Member Author

{
((Action)state)();
}
catch (Exception ex)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to catch the Exception? Currently assuming so as side-effect is quite bad - however is it always wrapped (for logging etc)

@KrzysztofCwalina
Copy link
Member

What are we doing with this PR? We have an API review of these APIs on Friday (I think) and it would be good to merge or close this one before.

@benaadams, @pakrym, @terrajobst, @davidfowl

@benaadams benaadams closed this Jan 11, 2018
@benaadams benaadams reopened this Jan 11, 2018
@benaadams
Copy link
Member Author

benaadams commented Jan 11, 2018

What are we doing with this PR?

Its just shooting yourself in the foot; perf-wise, not to use QueueUserWorkItem over Task.Run if you aren't interested in the Task (especially the preferLocal: true variant).

@@ -5,8 +5,11 @@ namespace System.Threading
{
public abstract class Scheduler
{
public static Scheduler TaskRun { get; } = new TaskRunScheduler();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you said so here #2026 (review)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have been more specific, why the syntax change.

Copy link
Member Author

@benaadams benaadams Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing it in a Scheduler field means the exact type gets lost for:

Scheduler.ThreadPool.Schedule((() => {})

So it remains a virtual call.

Storing it in an exact type field ThreadPoolScheduler means when Scheduler.ThreadPool inlines the Jit knows exactly what it is and can devitalize it to a direct call.

Won't directly help pipelines as the Pipe stores the configured values in a Scheduler field; but will help anyone calling it directly.

#elif NETSTANDARD2_0
Threading.ThreadPool.QueueUserWorkItem(_actionAsTask, action);
#else
Task.Factory.StartNew(action);
Copy link
Member

@davidfowl davidfowl Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this just be QueueUserWorkItem (I'm aware it ends up going to the global queue).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't exist on netstandard1.1 came in at netstandard2.0 😢

@@ -2,7 +2,7 @@
<Import Project="..\..\tools\common.props" />
<PropertyGroup>
<Description>An abstraction for doing efficient asynchronous IO</Description>
<TargetFramework>netstandard1.1</TargetFramework>
<TargetFrameworks>netstandard1.1;netstandard2.0;netcoreapp2.1</TargetFrameworks>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably the most unfortunate part of this change but meh..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meh indeed. It's in implementation details with zero bearings on the user's experience.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's in implementation details with zero bearings on the user's experience.

In this case yes.

{
// Create faulted Task for the TaskScheulder to handle exception
// rather than letting it escape onto the ThreadPool and crashing the process
Task.FromException(ex);
Copy link
Member

@davidfowl davidfowl Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty atypical. I think it should be left to crash. We don't do this anywhere else.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

K, will clean up the code a lot to remove it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

@davidfowl davidfowl merged commit addc27e into dotnet:master Jan 11, 2018
@dotnet dotnet deleted a comment from juliusfriedman Jan 11, 2018
@dotnet dotnet deleted a comment from juliusfriedman Jan 11, 2018
@dotnet dotnet deleted a comment from juliusfriedman Jan 12, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Devirtualization of Schedulers Task.Factory.StartNew is slower than QUWI for fire & forget tasks
5 participants