-
Notifications
You must be signed in to change notification settings - Fork 347
Scheduler improvements #2026
Scheduler improvements #2026
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,11 @@ namespace System.Threading | |
{ | ||
public abstract class Scheduler | ||
{ | ||
public static Scheduler TaskRun { get; } = new TaskRunScheduler(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because you said so here #2026 (review) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should have been more specific, why the syntax change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Storing it in a Scheduler.ThreadPool.Schedule((() => {}) So it remains a virtual call. Storing it in an exact type field Won't directly help pipelines as the |
||
public static Scheduler Inline { get; } = new InlineScheduler(); | ||
private static ThreadPoolScheduler _threadPoolScheduler = new ThreadPoolScheduler(); | ||
private static InlineScheduler _inlineScheduler = new InlineScheduler(); | ||
|
||
public static Scheduler ThreadPool => _threadPoolScheduler; | ||
public static Scheduler Inline => _inlineScheduler; | ||
|
||
public abstract void Schedule(Action action); | ||
public abstract void Schedule(Action<object> action, object state); | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Threading.Tasks; | ||
|
||
namespace System.Threading | ||
{ | ||
internal sealed class ThreadPoolScheduler : Scheduler | ||
{ | ||
public override void Schedule(Action action) | ||
{ | ||
#if NETCOREAPP2_1 | ||
// Queue to low contention local ThreadPool queue; rather than global queue as per Task | ||
Threading.ThreadPool.QueueUserWorkItem(_actionAsTask, action, preferLocal: true); | ||
#elif NETSTANDARD2_0 | ||
Threading.ThreadPool.QueueUserWorkItem(_actionAsTask, action); | ||
#else | ||
Task.Factory.StartNew(action); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't exist on |
||
#endif | ||
} | ||
|
||
public override void Schedule(Action<object> action, object state) | ||
{ | ||
#if NETCOREAPP2_1 | ||
// Queue to low contention local ThreadPool queue; rather than global queue as per Task | ||
Threading.ThreadPool.QueueUserWorkItem(_actionObjectAsTask, new ActionObjectAsTask(action, state), preferLocal: true); | ||
#elif NETSTANDARD2_0 | ||
Threading.ThreadPool.QueueUserWorkItem(_actionObjectAsTask, new ActionObjectAsTask(action, state)); | ||
#else | ||
Task.Factory.StartNew(action, state); | ||
#endif | ||
} | ||
|
||
#if NETCOREAPP2_1 || NETSTANDARD2_0 | ||
// Catches only the exception into a failed Task, so the fire-and-forget action | ||
// can be queued directly to the ThreadPool without the extra overhead of as Task | ||
private readonly static WaitCallback _actionAsTask = state => | ||
{ | ||
try | ||
{ | ||
((Action)state)(); | ||
} | ||
catch (Exception ex) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) |
||
{ | ||
// Create faulted Task for the TaskScheulder to handle exception | ||
// rather than letting it escape onto the ThreadPool and crashing the process | ||
Task.FromException(ex); | ||
} | ||
}; | ||
|
||
private readonly static WaitCallback _actionObjectAsTask = state => ((ActionObjectAsTask)state).Run(); | ||
|
||
private sealed class ActionObjectAsTask | ||
{ | ||
private Action<object> _action; | ||
private object _state; | ||
|
||
public ActionObjectAsTask(Action<object> action, object state) | ||
{ | ||
_action = action; | ||
_state = state; | ||
} | ||
|
||
// Catches only the exception into a failed Task, so the fire-and-forget action | ||
// can be queued directly to the ThreadPool without the extra overhead of as Task | ||
public void Run() | ||
{ | ||
try | ||
{ | ||
_action(_state); | ||
} | ||
catch (Exception ex) | ||
{ | ||
// Create faulted Task for the TaskScheulder to handle exception | ||
// rather than letting it escape onto the ThreadPool and crashing the process | ||
Task.FromException(ex); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. K, will clean up the code a lot to remove it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
||
} | ||
} | ||
} | ||
#endif | ||
} | ||
} |
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.
This is probably the most unfortunate part of this change but meh..
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.
Meh indeed. It's in implementation details with zero bearings on the user's experience.
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.
In this case yes.